Java多线程的实现方式
一、继承Thread
Thread 类本质上是实现了 Runnable 接口的一个实例,表明一个线程的实例。启动线程的惟一方法就是经过 Thread 类的 start()实例方法。 start()方法是一个 native 方法 ,它将启动一个新线程,并执行 run()方法。
demo:
package com.bitch.demo; public class MyThread extends Thread{ public void run() { System.out.println("hello,luyizhou"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("hello,lucian"); } }
二、实现Runnable接口
若是本身的类已经 extends 另外一个类,就没法直接 extends Thread,此时,能够实现一个Runnable 接口。
demo:
1 package com.bitch.demo; 2 3 public class MyThread extends HelloWorld implements Runnable{ 4 5 public void run() { 6 System.out.println("hello,luyizhou"); 7 try { 8 Thread.sleep(1000); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 System.out.println("hello,lucian"); 13 } 14 15 }
1 package com.bitch.demo; 2 3 public class ThreadTest { 4 5 public static void main(String[] args) { 6 7 System.out.println("111"); 8 MyThread myThread = new MyThread(); 9 10 Thread thread = new Thread(myThread); 11 thread.start(); 12 13 System.out.println("222"); 14 } 15 }
三、使用Callable和Future创建
上面的两种方式都有这两个问题:
- 无法获取子线程的返回值
- run方法不可以抛出异常
demo:
1 package com.bitch.demo; 2 3 import java.util.concurrent.Callable; 4 5 public class MyThread extends HelloWorld implements Callable { 6 7 public Object call() throws Exception { 8 System.out.println("hello,luyizhou"); 9 try { 10 Thread.sleep(1000); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 System.out.println("hello,lucian"); 15 return null; 16 } 17 }
1 package com.bitch.demo; 2 3 import java.util.concurrent.FutureTask; 4 5 public class ThreadTest { 6 7 public static void main(String[] args) { 8 9 System.out.println("111"); 10 MyThread myThread = new MyThread(); 11 12 FutureTask futureTask = new FutureTask(myThread); 13 new Thread(futureTask).start(); 14 15 System.out.println("222"); 16 } 17 }
四、使用线程池
线程池提供了一个线程队列,队列中保存着所有等待状态的线程,避免了创建与销毁额外开销,提高了响应的速度,建议大家使用这种方法创建、管理线程。
demo:
1 package com.bitch.demo; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 6 public class ThreadTest { 7 8 public static void main(String[] args) { 9 10 System.out.println("111"); 11 12 ExecutorService executorService = Executors.newFixedThreadPool(10); 13 executorService.execute(() -> System.out.println("这是个新的线程" + Thread.currentThread().getName())); 14 executorService.shutdown(); 15 16 System.out.println("222"); 17 } 18 }
五、对比
1 继承Thread类
- 实现简单,直接继承Thread即可。并且在run()方法内获取当前线程直接使用this
就可以了,无须使用Thread.currentThread() 方法; - java当中的继承只能是单继承,一个类只能继承一个直接父类。如果一个类继承了Thread类,就不能有其他的父类。
- 创建的对象,即封装了线程任务,又封装了线程对象的特点(线程对象),不同的东西封装到了一个对象之中,不符合java面向对象的特点。
2 实现Runnable接口
- run()方法内获取当前线程不能使用使用this,必须使用Thread.currentThread() 方法;
- 将线程任务单独的封装到一个接口实现类当中,将线程任务和线程对象进行了分离:Runnable接口实现类当中定义线程任务,Thread类封装了线程对象,将不同的功能封装到不同的对象之中,这种思想更加的符合面向对象的特点。
- 避免了单继承带来的局限性。
- 适合多条线程处理同一个资源的情况,很容易的实现资源共享。需要多个线程完成一个任务时,比如:多个线程共同卖100张票,他们需要共享100张票这个资源。
3 实现Callable接口
具有实现Runnable接口的特点,同时还能获取返回值,并且可以抛出异常。