Java多线程的三种实现方式

今天简单说一下Java三种多线程实现方式和区别,主要有实现Runnable、Callable和继承Thread三种方式。java

实现Runnable的方式多线程

这种方式比较经常使用,当咱们的线程类有继承其余的类的状况下(Java不支持类多继承),而且线程任务不须要返回值的状况下能够选用这种方式。ide

 1 public class ThreadRunnableDemo implements Runnable{
 2 
 3     /** 计数变量 */
 4     private int count = 0;
 5     
 6     public static void main(String[] args) throws InterruptedException {
 7         
 8         ThreadRunnableDemo threadRunnableDemo = new ThreadRunnableDemo();
 9         
10         //实例化线程
11         Thread thread = new Thread(threadRunnableDemo, "threadRunnableDemoA");
12         System.out.println(String.format("线程状态preStart: %s", thread.getState()));
13         
14         //启动线程
15         thread.start();
16         System.out.println(String.format("线程状态afterStart: %s", thread.getState()));
17         
18         //主线程休眠1000ms
19         Thread.sleep(1000);
20         System.out.println(String.format("线程状态after1000ms: %s", thread.getState()));
21 
22     }
23 
24     @Override
25     public void run() {
26         
27         count++;
28         
29         System.out.println(String.format("线程名称:%s, 线程状态:%s, count:%s", 
30                 Thread.currentThread().getName(), Thread.currentThread().getState(), count));
31         
32     }
33 }

输出结果:测试

1 线程状态preStart: NEW
2 线程状态afterStart: RUNNABLE
3 线程名称:threadRunnableDemoA, 线程状态:RUNNABLE, count:1
4 线程状态after1000ms: TERMINATED

 

实现Callable的方式spa

当咱们执行线程须要返回值的时候那么就必须选用实现Callable类的方式,由于目前只有这种方式能返回值。固然这种方式咱们也能够不须要获取返回值。线程

这种方式是经过FutureTask的get()方法(下面代码的第22行)或者get(long timeout, TimeUnit unit)(下面代码的第28行)方法获取返回值。当咱们看Callable的接口定义的源码会发现“public interface Callable<V> ” ,咱们实现的时候是须要定义返回类型,以下面代码所示。code

除此以外咱们还须要注意的是:当咱们经过FutureTask的get()方法去获取线程的返回值的时候是要等到线程call()内容都执行完毕以后才能获取获得,而且get()方法后面的代码必须等待,说明这必定是同步的,因此咱们能够在真正须要线程返回值的时候才经过get()方法去获取,以避免被阻塞。当咱们经过get(long timeout, TimeUnit unit)方式去获取的时候能够设置超时时间,若是超过所设置的超时时间都没有获取到线程返回的值则会抛出 java.util.concurrent.TimeoutException 异常,固然若是在get(long timeout, TimeUnit unit)以前用get()方式获取了的话就不会抛异常。orm

实现Callable还有个好处就是能够线程能够抛异常,若是咱们须要在线程里抛出异常的话也能够选用这种方式,其余两种方式只能捕获异常信息。blog

 1 public class ThreadCallableDemo implements Callable<Integer>{
 2     
 3     /** 计数变量 */
 4     private int count = 0;
 5 
 6     public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
 7         
 8         ThreadCallableDemo threadCallableDemo = new ThreadCallableDemo();
 9         
10         //经过FutureTask获取返回值
11         FutureTask<Integer> taskA = new FutureTask<>(threadCallableDemo);
12         
13         //实例化线程
14         Thread thread = new Thread(taskA, "threadCallableDemoA");
15         System.out.println(String.format("线程状态preStart: %s", thread.getState()));
16         
17         //启动线程
18         thread.start();
19         System.out.println(String.format("线程状态afterStart: %s", thread.getState()));
20         
21         //经过FutureTask的get()方法获取返回值
22         int result = taskA.get();
23         System.out.println("是否同步测试....");
24         System.out.println(String.format("result: %s", result));
25         System.out.println(String.format("线程状态afterGetResult1: %s", thread.getState()));
26         
27         //经过FutureTask的get()方法获取返回值 设置超时时间 单位为ms
28         int resultWithTime = taskA.get(100, TimeUnit.MILLISECONDS);
29         System.out.println(String.format("resultWithTime: %s", resultWithTime));
30         System.out.println(String.format("线程状态afterGetResult2: %s", thread.getState()));
31         
32     }
33 
34     /**
35      * 实现Callable的call类
36      */
37     @Override
38     public Integer call() throws Exception {
39         
40         //自增
41         count++;
42         
43         System.out.println(String.format("线程名称:%s, 线程状态:%s, count:%s", 
44                     Thread.currentThread().getName(), Thread.currentThread().getState(), count));
45         System.out.println("休眠1000ms....");
46         Thread.currentThread().sleep(1000);
47         return count;
48     }
49 }

输出结果:继承

1 线程状态preStart: NEW
2 线程状态afterStart: RUNNABLE
3 线程名称:threadCallableDemoA, 线程状态:RUNNABLE, count:1
4 休眠1000ms....
5 是否同步测试....
6 result: 1
7 线程状态afterGetResult1: TERMINATED
8 resultWithTime: 1
9 线程状态afterGetResult2: TERMINATED

 

继承Thread的方式 

Thread类实际上也是实现Runnable接口,因此当咱们继承Thread的时候咱们即便不实现run()方法也不会报错,这种方式也常常用。

下面我写了两种不一样继承Thread的代码,你们能够看一下区别,我在网上看到不少人说 继承Thread实现多线程,线程间不能共享数据,可是我用下面的代码1方式彷佛也能够共享哇,欢迎你们提出质疑。

代码1:

 1 public class ThreadThreadDemo extends Thread{
 2 
 3     /** 计数变量 */
 4     private int count = 0;
 5     
 6     public static void main(String[] args) throws InterruptedException {
 7         
 8         ThreadThreadDemo  threadThreadDemo = new ThreadThreadDemo();
 9         
10         //实例化线程
11         Thread thread = new Thread(threadThreadDemo, "threadThreadDemoA");
12         System.out.println(String.format("线程状态preStart: %s", thread.getState()));
13         
14         //启动线程
15         thread.start();
16         System.out.println(String.format("线程状态afterStart: %s", thread.getState()));
17         
18         //主线程休眠1000s
19         Thread.sleep(1000);
20         System.out.println(String.format("线程状态after1000ms: %s", thread.getState()));
21     }
22     
23     @Override
24     public void run() {
25         
26         count++;
27         
28         System.out.println(String.format("线程名称:%s, 线程状态:%s, count:%s", 
29                 Thread.currentThread().getName(), Thread.currentThread().getState(), count));
30     }
31 }

输出结果1:

1 线程状态preStart: NEW
2 线程状态afterStart: RUNNABLE
3 线程名称:threadThreadDemoA, 线程状态:RUNNABLE, count:1
4 线程状态after1000ms: TERMINATED

 代码2:

 1 public class ThreadThreadDemo extends Thread{
 2 
 3     /** 计数变量 */
 4     private int count = 0;
 5     
 6     public static void main(String[] args) throws InterruptedException {
 7         
 8         ThreadThreadDemo  threadThreadDemo = new ThreadThreadDemo();
 9         
10         //实例化线程
11         System.out.println(String.format("线程状态preStart: %s", threadThreadDemo.getState()));
12         
13         //启动线程
14         threadThreadDemo.start();
15         System.out.println(String.format("线程状态afterStart: %s", threadThreadDemo.getState()));
16         
17         //主线程休眠1000s
18         Thread.sleep(1000);
19         System.out.println(String.format("线程状态after1000ms: %s", threadThreadDemo.getState()));
20     }
21     
22     @Override
23     public void run() {
24         
25         count++;
26         
27         System.out.println(String.format("线程名称:%s, 线程状态:%s, count:%s", 
28                 Thread.currentThread().getName(), Thread.currentThread().getState(), count));
29     }
30 }

输出结果2:

1 线程状态preStart: NEW
2 线程状态afterStart: RUNNABLE
3 线程名称:Thread-0, 线程状态:RUNNABLE, count:1
4 线程状态after1000ms: TERMINATED

 

最后总结:

  1. 若是不要求线程返回结果,也不须要抛异常也没有继承其余的类,那么三种方式能够任选,看喜爱;
  2. 若是有继承其余类,那么就只能用实现Runnable和实现Callable的方式;
  3. 若是须要线程返回结果或者须要线程抛异常那么选择实现Callable的方式的方式,可是须要注意的是获取返回结果是同步的方式。

若是有疑问或者有问题欢迎留言讨论!

相关文章
相关标签/搜索