Java 并发编程笔记 - 创建线程的 ?种方法
Posted 笑虾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 并发编程笔记 - 创建线程的 ?种方法相关的知识,希望对你有一定的参考价值。
Java 并发编程笔记 - 创建线程的 ?种方法
严格的说创建线程只有实现 Runnable 接口一种方法,其他都是间接实现 Runnable
- Thread 实现 Runnable
- Callable 是无法直接起的,要通过 RunnableFuture 联姻。(FutureTask 实现了 RunnableFuture )
- 线程池创建直接返回的都是 Future 可想而知。
Thread 类
Java 只能单继承,所以一般不会这么用。
- 直接继承 Thread 重写 run
- 再调 start() 启动
public class ThreadDemo extends Thread
private int i = 10;
@Override
public void run()
while (i > 0)
System.out.println("线程 " + Thread.currentThread().getName() + " 输出:" + i);
i--;
public static void main(String[] args) throws InterruptedException
System.out.println("线程 " + Thread.currentThread().getName() + "开始。");
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
Runnable 接口
- 实现 Runnable 重写 run
- 没有返回值
- 启动:两种
3.1. 丢进Thread
再.start()
3.2. 用ExecutorService
启动线程
public class RunnableDemo implements Runnable
private int i = 10;
@Override
public void run()
while (i > 0)
System.out.println("线程 " + Thread.currentThread().getName() + " 输出:" + i);
i--;
public static void main(String[] args) throws InterruptedException
// 用 Thread.start() 启动
System.out.println("线程 " + Thread.currentThread().getName() + "开始。");
new Thread(new RunnableDemo()).start();
// Runnable 也可以用 ExecutorService 启动线程,比 Thread 的 start() 更好
ExecutorService executor = Executors.newCachedThreadPool();
RunnableDemo runnableDemo = new RunnableDemo();
executor.execute(runnableDemo);
executor.shutdown();
Callable 接口
- 实现
Callable<T>
重写call
- 有返回值。返回值类型
T
。大概套路:
2.1. 提前说明一下关系:FutureTaskimplements
RunnableFutureextends
Runnable, Future。(血脉凑齐)
2.2. 先用Callable
对象作为参数
实例化一个FutureTask
。拿到一个Future
对象,它有两个用途:
2.2.1. 首先Future
对象是对将来
的一个抽象,所以将来
可以通过它获得最终
结果。(是不是有Promise的感觉)
2.2.2. 其次FutureTask
是Runnable
的实现,所以可以丢进Thread
。 - 启动三种:
3.1. 用FutureTask
包装一下丢进Thread
再.start()
。
3.2. 用ExecutorService
启动线程
3.3.new Callable()
先丢进FutureTask
再交给ExecutorService
提交 Future<T>.get()
获取线程返回值
public class CallableDemo implements Callable<Integer>
private int i = 10;
@Override
public Integer call() throws Exception
while (i > 0)
System.out.println("线程 " + Thread.currentThread().getName() + " 输出:" + i);
i--;
return 999;
public static void main(String[] args) throws InterruptedException, ExecutionException
System.out.println("线程 " + Thread.currentThread().getName() + "开始。");
// FutureTask 是 Runnable 的实现,所以也可以丢给 Thread().start();
new Thread(new FutureTask<Integer>(new CallableDemo()), "AAA").start();
// Callable 只能用 ExecutorService 启动线程
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> submit = executor.submit(new CallableDemo());
executor.shutdown();
System.out.println("线程结束,返回:" + submit.get());
// 先丢进 FutureTask 再提交
ExecutorService executor2 = Executors.newCachedThreadPool();
FutureTask<Integer> futureTask = new FutureTask<Integer>(new CallableDemo());
executor2.submit(futureTask);
executor2.shutdown();
System.out.println("线程结束,返回:" + futureTask.get());
多线程虚假唤醒
对比两个方法对wait();
的判断处理。
吃粉()
的判断在if 代码块
中,下次醒来时,会直接往下走。但我们想要的是被唤醒后,首先判断是否满足条件,满足的情况下才处理业务。所以这里会有漏网之鱼。
下粉()
因为用的while
判断,下次原地醒来,继续走完代码块,又回头判断一次。必须完足条件才会继续,不存在漏网之鱼。
class 牛肉粉
private int i = 0;
public synchronized void 吃粉() throws InterruptedException
if (i == 0)
// 在 wait() 调用时,释放锁,就地睡觉。
this.wait();
// 被唤醒时,原地站起来紧跟在 wait()后继续执行。
System.out.println(i + " 碗库存!" + Thread.currentThread().getName() + " 吃了一碗粉。");
i--;
this.notifyAll();
public synchronized void 下粉() throws InterruptedException
while (i != 0)
this.wait();
System.out.println(i + " 碗库存!" + Thread.currentThread().getName() + " 下了一碗粉。");
i++;
this.notifyAll();
参考资料
以上是关于Java 并发编程笔记 - 创建线程的 ?种方法的主要内容,如果未能解决你的问题,请参考以下文章