我们上一节当中讲到了创建线程的第一种方法,就是继承Thread类,覆写Thread当中的run方法,然后创建子类对象,之后调用对象的start方法启动线程。但是这种方法有一个缺陷,因为我们知道在java当中类与类当中是单继承的关系,假如现在我们的子类是另外一个类的子类,这个时候如果这个子类想使用多线程的话,就没有办法了。我们之前说接口的时候,知道接口的存在就是为了扩展类的功能,而避免多继承。那么有没有一种方法可以通过实现接口来完成多线程的创建呢?我们查阅Api可以知道,在java当中为我们提供了一个Runnable接口。在查阅文档的同时,我们知道在Runnable这个接口当中,只有一个run方法。我们只能实现Runnable这个接口中的方法,但是我们知道用在Runnable接口当中只有一个run方法,但是线程的启动需要start()方法,那么这个时候应该怎么办呢?在Thread类中有一个构造函数,他接受一个Runnable类型的参数,然后创建一个线程。在Runnable的run方法当中,也有一个说明是说:需要启动一个线程来调用Runnable当中的run方法。
代码实例(用Runnable来创建线程):
1 class Demo4 implements Runnable 2 { 3 4 public void run() 5 { 6 7 for(int i = 0; i<=10 ; i++) 8 System.out.println("Dangqianxiancheng"+Thread.currentThread().getName()+"i is "+i); 9 10 } 11 12 } 13 14 class ThreadDemo4 15 { 16 17 public static void main(String[] args) { 18 19 Demo4 d = new Demo4(); 20 Thread t1 = new Thread(d); 21 Thread t2 = new Thread(d); 22 t1.start(); 23 t2.start(); 24 25 } 26 27 }
在这种方法当中我们创建线程的步骤就是:
1、定义一个类然后实现Runnable当中的run方法
2、创建该类实例
3、创建线程对象,并且把上个类的实例当作构造参数传入该线程对象
4、调用线程对象的start()方法,开启线程。
细节:在用这种方式创建线程对象的时候,这里有几个需要注意的地方。第一个就是本身在Thread类当中就有一个run方法,但是我们实现的Runnable接口当中也有一个run方法,这个时候就存在一个问题。就是,当我们调用run方法的时候到底是使用的那一个run方法呢?这个时候就用到了策略模式。其实这个时候,在构造函数的时候,先判定当前的对象是否有传入的参数,如果有传入的参数就调用传入的参数即Runnable接口的run方法,如果没有就调用本身的run方法,在代码上的体现就是:
1 class Thread() 2 { 3 4 private Runnable r; 5 Thread(){} 6 Thread(Runnable r) 7 { 8 9 this.r = r; 10 11 } 12 public void run() 13 { 14 15 if(r != null) 16 r.run(); 17 18 } 19 public void start() 20 { 21 22 } 23 24 }
这个时候就确定应该调用谁的方法了。
Runnable线程的设计思想:
在创建线程的第一种方式当中,要创建线程必须继承Thread类,但是继承Thread类之后,该类也成了Thread类的体系,具备了Thread当中那些自己并不大需要的方法。并且该类一旦继承Thread类之后就成了他的体系了。此时我们把其中的任务分离出来,之后把他封装成接口。这样就能够让其他的类继承这个接口,然后把这个接口传入到Thread的对象当中来调用,这样就避免了java单继承的局限性,也降低了任务与线程之间的耦合性。
Runnable接口的好处:
1、将任务从线程当中抽离出来,进行了封装,把任务封装成了对象。
2、避免了java单继承的局限性。
一般这种创建方法比较常用。