1、继承Thread类:
步骤:①、定义类继承Thread;
1 public class ThreadDemo1 { 2 3 public static void main(String[] args) { 4 5 //创建两个线程 6 ThreadDemo td = new ThreadDemo("zhangsan"); 7 ThreadDemo tt = new ThreadDemo("lisi"); 8 //执行多线程特有方法,如果使用td.run();也会执行,但会以单线程方式执行。 9 td.start(); 10 tt.start(); 11 //主线程 12 for (int i = 0; i < 5; i++) { 13 System.out.println("main" + ":run" + i); 14 } 15 } 16 } 17 //继承Thread类 18 class ThreadDemo extends Thread{ 19 20 //设置线程名称 21 ThreadDemo(String name){ 22 super(name); 23 } 24 //重写run方法。 25 public void run(){ 26 for(int i = 0; i < 5; i++){ 27 System.out.println(this.getName() + ":run" + i); //currentThread() 获取当前线程对象(静态)。 getName() 获取线程名称。 28 } 29 } 30 }
2、实现Runnable接口: 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参方法。
实现步骤: ①、定义类实现Runnable接口
②、覆盖Runnable接口中的run方法
将线程要运行的代码放在该run方法中。
③、通过Thread类建立线程对象。
④、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程执行指定对象的run方法就要先明确run方法所属对象
⑤、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
public class RunnableDemo { public static void main(String[] args) { RunTest rt = new RunTest(); //建立线程对象 Thread t1 = new Thread(rt); Thread t2 = new Thread(rt); //开启线程并调用run方法。 t1.start(); t2.start(); } } //定义类实现Runnable接口 class RunTest implements Runnable{ private int tick = 10; //覆盖Runnable接口中的run方法,并将线程要运行的代码放在该run方法中。 public void run(){ while (true) { if(tick > 0){ System.out.println(Thread.currentThread().getName() + "..." + tick--); } } } }
3、通过Callable和Future创建线程:
实现步骤:①、创建Callable接口的实现类,并实现call()方法,改方法将作为线程执行体,且具有返回值。
②、创建Callable实现类的实例,使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
③、使用FutureTask对象作为Thread对象启动新线程。
④、调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
1 public class CallableFutrueTest { 2 public static void main(String[] args) { 3 CallableTest ct = new CallableTest(); //创建对象 4 FutureTask<Integer> ft = new FutureTask<Integer>(ct); //使用FutureTask包装CallableTest对象 5 for(int i = 0; i < 100; i++){ 6 //输出主线程 7 System.out.println(Thread.currentThread().getName() + "主线程的i为:" + i); 8 //当主线程执行第30次之后开启子线程 9 if(i == 30){ 10 Thread td = new Thread(ft,"子线程"); 11 td.start(); 12 } 13 } 14 //获取并输出子线程call()方法的返回值 15 try { 16 System.out.println("子线程的返回值为" + ft.get()); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } catch (ExecutionException e) { 20 e.printStackTrace(); 21 } 22 } 23 } 24 class CallableTest implements Callable<Integer>{ 25 //复写call() 方法,call()方法具有返回值 26 public Integer call() throws Exception { 27 int i = 0; 28 for( ; i<100; i++){ 29 System.out.println(Thread.currentThread().getName() + "的变量值为:" + i); 30 } 31 return i; 32 } 33 }
三种方法对比:
继承Thread:线程代码存放在Thread子类run方法中。
优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。
劣势:已经继承了Thread类,无法再继承其他类。
实现Runnable:线程代码存放在接口的子类的run方法中。
优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。
实现Callable:
优势:有返回值、避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法
建议使用实现接口的方式创建多线程。