天天看点

【多线程】——Thread VS Runnable

进程和线程的关系

    多个线程构成一个进程,线程是进程中的一个元素,例如QQ.exe查看电脑进程的时候发现只有一个进程,但是我们可以同时和多个用户聊天交流,而且可以一边聊天,刷空间之类。对每一个用户的聊天就是一个线程,多个用户的互动构成进程。

    演示一个不使用多线程的Demo,也就是单线程

public class SingleDemo{
  public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.run();
    while(true){
      System.out.println("Main方法在运行");
    }
  }
}
  
  class MyThread{
    public void run(){
      while (true){
        System.out.println("MyThread类的run()方法在运行");
      }
    }
  }      

  根据demo可以知道mian中的run方法永远都不可能被执行

【多线程】——Thread VS Runnable

      一张图说明何为单线程和多线程!

【多线程】——Thread VS Runnable

 从图中很清晰表明我们使用多线程的原因

继承Thread创建多线程

public class DemoThread{
  public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.start(); //通过start()开启了一个新的线程
    while(true){
      System.out.println("run()方法在运行");
    }
  }
}
class MyThread extends Thread {
  public void run(){
    while(true){
      System.out.println("MyThread类的run()方法在运行");
    }
  }
}      

显示结果

【多线程】——Thread VS Runnable

实现Runnable接口创建多线程

public class DemoRunnable{
  public static void main(String[] args){
    RunnableDemo runnable = new RunnableDemo();
    Thread mythread = new Thread(runnable);
    mythread.start();
    while(true){
      System.out.println("main类的run()方法在运行");
    }
  }
}
class RunnableDemo implements Runnable{
  public void run(){
    while(true){
      System.out.println("RunnableDemo类的run()方法在运行");
    }
  }
}      

显示结果

【多线程】——Thread VS Runnable

目前实现多线程的方式继承Thread,另一种实现Runnable接口。

上述Demo是利用Thread(Runnable target)这个构造函数实现的,Runnable是一个接口其中只有一个run()方法,在调用Thread时,看一下Thread的类结构就知道,其实实现的是接口Runnable中的方法。所以两种多线程实现方式具有多态关系。

Thread VS Runnable

    先说一个例子,火车站售票会牵扯到一个资源共享的问题,资源就是车票,每个售票都相当与一个线程,假如有100张票,每张票理论上都只能买一个人,下面看Thread和Runnable的处理方式

继承Thread

public class DemoExceple{
  public static void main(String[] args){
    new TicketWindow().start();
    new TicketWindow().start();
    new TicketWindow().start();
    new TicketWindow().start();
  }
}
class TicketWindow extends Thread{
    private int tickets = 100;
    public void run(){
      while(true){
        if(tickets>0){
          Thread th = Thread.currentThread();
          String name = th.getName();
          System.out.println(name+"正在发售第"+tickets--+"张票");
        }
      }
    }
  }      

运行结果

【多线程】——Thread VS Runnable

    根据这个运行结果,发现每一张票都被重复卖了四次,明显这种多线程的方式并不太适合资源共享的问题。

实现Runnable接口

public class RunnableDemoTest{
  public static void main(String[] args){
    TicketWindow tw = new TicketWindow();
    new Thread(tw,"窗口1").start();
    new Thread(tw,"窗口2").start();
    new Thread(tw,"窗口3").start();
    new Thread(tw,"窗口4").start();
  }
  
}
class TicketWindow implements Runnable{
  private int tickets = 100;
  public void run(){
    while(true){
      if(tickets>0){
        Thread th = Thread.currentThread();
        String th_name = th.getName();
        System.out.println(th_name+"正在发售第"+tickets--+"张票");
      }
    }
  }
}      

运行结果

【多线程】——Thread VS Runnable

根据运行结果发现使用Runnable接口刚好能解决我们资源共享的问题。

为什么Thread不行,而Runnable就可以?

Thread方式中创建了4个Thread对象,4个线程分别执行4个对象中的代码,所以4个线程是独立的去完成卖票任务

Runnable方式,同样创建了4个Thread对象,但是只有一个Runnable对象,4个Thread对象共享Runnable中的代码,因此,便会出现4个线程同时完成卖票的任务的结果。如果创建4个Runnable对象,分别做为参数传入4个Thread中,结果会和Thread方式一样的。

    其实实现Runnable接口的线程中如果出现休眠,在资源共享也会出现非线程安全的问题,最根本的解决方式资源共享的问题还是同步锁(synchronized)的机制。

结论

   根据上述两种情况,其实Runnable和Thread能完成相同的功能,毕竟Thread也是实现Runnable,两者根本的区别一个是继承,一个是实现。

1、Runnable相当于一个作业,而Thread才是真正的处理线程。通过new Thread(Runnable target)把作业交给线程去处理,这样达到松耦合的效果,也是符合面向对象中组合的使用。

继续阅读