前言
每天积累一点点,积跬步至千里。今天学习
JUC
包中的Condition、Callable&Future。
Condition等待与唤醒
JUC
提供了这么多的工具类,目的是让我们对于程序中多线程环境下,对线程的控制,Conditon
对象,用来让指定的线程等待与唤醒,按照我们预期的顺序执行,大白话就是,我们完全掌控线程的执行顺序。 注意: 它必须和ReentrantLock
重入锁配合使用。Condition
用于替代wait()/notify()
方法
notify
只能随机唤醒等待的线程,而Condition
可以唤醒指定线程,这有利于更好的控制并发程序。
Condition核心方法
await()
阻塞当前线程,直到signal()唤醒signal()
唤醒被await()
的线程,从中断处继续执行signalAll()
唤醒所有被await()
阻塞的线程
代码示例
- 创建三个线程,分别打印
1
、2
、3
,为了效果明显加了1000ms
睡眠,正常情况下按顺序打印肯定是1
、2
、3
- 但是现在我们想要打印
3
、1
、2
,这时就可以利用Condition
来实现控制,看下面代码
public class ConditionSample { public static void main(String[] args) throws InterruptedException { ReentrantLock lock = new ReentrantLock(); Condition c1 = lock.newCondition(); Condition c2 = lock.newCondition(); new Thread(() -> { lock.lock(); try { c1.await();//阻塞当前线程 Thread.sleep(1000); System.out.println(1); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); new Thread(() -> { lock.lock(); try { c2.await();//阻塞当前线程 Thread.sleep(1000); System.out.println(2); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); new Thread(() -> { lock.lock(); try { Thread.sleep(1000); System.out.println(3); c1.signal(); c2.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); } }
我们通过
ReentrantLock
对象创建了2
个Condition
对象c1
、c2
.相当于两个标记锁,分别加在打印1
和2
的线程上,等3
打印完成,再去控制先唤醒哪个,先唤醒哪个则哪个打印输出,实现预期效果。
Callable&Future
- Callable和Runnable一样用来创建线程,区别在于Callable有返回值并且可以抛出异常
- Future是一个接口。它用于表示异步计算的结果。提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。
代码示例
获取
10000
以内所有的质数,单线程循环查找的做法这里就不做介绍了,看下面示例代码,我们可以通过多线程的方式去判断是否为质数,然后将结果接收返回。这里获取质数的方法比较简单,如果换成更为复杂的逻辑,多线程的效率优势就会很明显了。
public class FutureSample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 2; i <= 10000; i++) { Computor c = new Computor(); c.setNum(i); Future<Boolean> result = executorService.submit(c); try { Boolean r = result.get(); if (r) { System.out.println(c.getNum()); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } executorService.shutdown(); } } class Computor implements Callable<Boolean> { private Integer num; public Integer getNum() { return num; } public void setNum(Integer num) { this.num = num; } @Override public Boolean call() throws Exception { boolean isprime = true; for (int i = 2; i < num; i++) { if (num % i == 0) { isprime = false; break; } } return isprime; } }
Future
是对用于计算的线程进行监听,因为计算是在其他线程中执行的,所以这个返回结果的过程是异步的executorService.submit(c);
将c
对象提交给线程池,如有空闲线程立即执行里面的call
方法result.get();
用于获取返回值,如果线程内部的call
没有执行完成,则进入等待状态,直到计算完成