java多线程的三种实现方式

sunshine      2022-05-17     630

关键词:

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

实现Runnable的方式

这种方式比较常用,当我们的线程类有继承其他的类的情况下(Java不支持类多继承),并且线程任务不需要返回值的情况下可以选用这种方式。

 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的方式

当我们执行线程需要返回值的时候那么就必须选用实现Callable类的方式,因为目前只有这种方式能返回值。当然这种方式我们也可以不需要获取返回值。

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

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

实现Callable还有个好处就是可以线程可以抛异常,如果我们需要在线程里抛出异常的话也可以选用这种方式,其他两种方式只能捕获异常信息。

 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的方式的方式,但是需要注意的是获取返回结果是同步的方式。

如果有疑问或者有问题欢迎留言讨论!

 

 

java多线程实现的三种方式(代码片段)

文章目录实现多线程方式一:继承Thread类方法介绍实现步骤代码演示思考问题实现多线程方式二:实现Runnable接口Thread构造方法实现步骤代码演示实现多线程方式三:实现Callable接口方法介绍实现步骤代码演示三种实现方式... 查看详情

ajpfx关于java多线程实现的三种方式

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。 1、继承Thread类实现多线程... 查看详情

java多线程实现的三种方法,附两个线程执行不同的输出

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、继承Thread类实现多... 查看详情

java-多线程-创建线程的三种方式

JAVA-多线程-创建线程的三种方式并发:同一时间只有一条指令在执行,多个进程的指令被快速轮换执行。并行:同一时间有多条指令在多个处理器上运行。进程:每个运行中的程序就是一个进程。线程:线程(Thread)也被称为轻... 查看详情

java多线程《ii》—启动线程的三种方式和源码分析(代码片段)

...家见面啦,总算挑出点时间写文章了,写一下多线程吧,后面还会继续更新,文章内容若有问题请指出,万分感谢!好啦,下面就开始今天的课程吧!1、继承Th 查看详情

大数据必学java基础(七十六):创建线程的三种方式(代码片段)

文章目录创建线程的三种方式一、继承Thread类二、实现Runnable接口三、实现Callable接口创建线程的三种方式一、继承Thread类在学习多线程之前,以前的代码是单线程的吗?不是,以前也是有三个线程同时执行的。现在... 查看详情

java——多线程高并发系列之创建多线程的三种方式(threadrunnablecallable)(代码片段)

...)方法)写在前面历时一个星期,终于整完了Java多线程高并发这个系 查看详情

实现多线程的三种方式

p.MsoNormal,li.MsoNormal,div.MsoNormal{margin:0cm;margin-bottom:.0001pt;text-align:justify;font-size:10.5pt;font-family:"Calibri","sans-serif"}h1{margin-right:0cm;margin-left:0cm;font-size:24.0pt;font 查看详情

java多线程

Java多线程实现的三种方式Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、... 查看详情

多线程

JAVA多线程实现的三种方式Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、... 查看详情

java多线程开启的三种方式

1、继承Thread类,新建一个当前类对象,并且运行其start()方法1packagecom.xiaostudy.thread;23/**4*@desc第一种开启线程的方式5*@authorxiaostudy6*7*/8publicclassDemo1_ThreadextendsThread{910publicvoidrun(){11for(inti=0;i<10;i++){12Syste 查看详情

java创建线程的三种主要方式

Java创建线程的主要方式一、继承Thread类创建  通过继承Thread并且重写其run(),run方法中即线程执行任务。创建后的子类通过调用start()方法即可执行线程方法。  通过继承Thread实现的线程类,多个线程间无法共享线程类的实... 查看详情

java创建线程的三种方式

http://blog.csdn.net/longshengguoji/article/details/41126119线程的四种创建方式:(1)继承Thread类(2)实现Runnable接口(3)应用程序可通过使用Executor框架来创建线程池(4)实现callable接口线程的几种可用状态(1)新建(2)可运行(3)运... 查看详情

第五周作业(java多线程创建的三个方法)

  我最近在学习Java中多线程,并且觉得多线程这块在以后的Java开发中显得极为重要,就谈一下Java实现多线程的三种方式。JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实... 查看详情

多线程开启的三种方式

...st(inti){Console.WriteLine("test"+i);return100;Thread.Sleep(10);//让当前线程休眠(暂停当前线程的执行)单位为毫秒ms}staticvoidMain(string[]args)//在main方法中执行一个线程的执行是从上往下执行的{//通过委托来开启一个线程//Func<int,i 查看详情

创建线程的三种方式的对比?

(1)采用实现Runnable、Callable接口的方式创建多线程。优势是:线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线... 查看详情

java创建线程的三种方式,同步锁的实现synchronized,lock(代码片段)

一、继承Thread类创建通过继承Thread并且重写其run()方法,通过调用start()方法即可执行线程方法。写法1:publicclassMyThreadextendsThread@Overridepublicvoidrun()for(inti=0;i<15;i++)System.out.println(getName()& 查看详情

关于java的多线程

进程process线程Threadmain称之为主线程,为系统的入口,用于执行整个程序线程创建的三种方式:继承Thread类实现Runnable接口实现Callable接口继承Thread类:publicclassTestextendsThread@Override 查看详情