java.util.concurrent并发包提供了很多处理多线程的接口和类,主要包括:
- 用于线程同步的Lock锁接口。
- 用于线程通信的Condition条件接口。
- 支持异步运算的Callable接口和Future接口。
Lock锁
Lock锁的优势在于它提供了更灵活的获取同步代码块的锁的方式:
- lock():当前线程获取同步代码块的锁。
- tryLock():当前线程试图获取同步代码块的锁,如果锁正在被其他线程持有,返回false。
- tryLock(long time,TimeUnit unit):在时间返回内获取到同步代码块的锁,返回true;否则返回false。
Lock接口有一个实现类ReentrantLock,它有以下构造方法:
- ReentrantLock():默认构造方法,创建一个常规的锁。
- ReentrantLock(boolean fair):如果fair参数为true,会常见一个带公平策略的锁。否则就创建一个常规的锁。所谓公平策略,是指会让阻塞时间较长的线程有机会获得锁。
使用公平锁时需要注意:公平锁是以降低运行性能为代价的;公平锁依赖底层的线程调度的实现,不能完全保证公平。
采用Lock锁的编程模式:
public class LockTest {
private final ReentrantLock lock = new ReentrantLock();//创建锁
public void method() {
lock.lock();//获得锁
try {
//... 需要同步的原子操作
} finally {
lock.unlock();//释放锁
}
}
}
用于线程通信的Condition接口
java.util.concurrent.locks.Conditions条件接口用于线程之间的通信。Lock接口的newCondition()方法返回实现了Condition接口的实例。
Condition接口有以下方法:
- await():与Object的wait()方法相似。
- await(long time,TimeUnit unit):当前线程在参数设定的时间范围内被其他线程唤醒,返回true;否则返回false。
- signal():与Object类的notice()方法相似。
- signalAll():与Object类的noticeAll()方法相似。
支持异步运算的Callable接口和Future接口
Runnable接口的run()方法返回类型为void。假如线程A执行一个运算任务,线程B需要获取线程A的运算结果?直接用编程来实现,需要定义一个存放结果的共享变量,线程A、B都可以访问这个共享变量,并且需要对共享变量的代码块进行同步。
Callable和Future接口提供了更简单的操作。
- Callable接口:是在call()方法中指定线程所要执行的操作的,并且该方法有返回值
<V>
,它不能像Runnable实例那样作为Thread类的构造方法的参数。 - Future接口:能够保存异步运算的结果。它有以下方法:
get():返回异步运算的结果,如果结果还没出来,当前线程就会阻塞。
get(long time,TimeUnit unit):如果超出了参数设定的时间范围还没有返回结果,就会抛出异常TimeoutException。
cancel(boolean mayInterrupt):取消该运算。如果运算还没开始,就立即取消。如果运算已经开始,并且mayInterrupt设为 true,那么会取消运算;如果mayInterrupt设为false,那么不会取消运算。
isCancelled():判断运算是否已经取消。
isDone():判断运算是否已经完成。 - FutureTask():他是一个适配器,同时实现了Runnable和Future接口,同时会关联一个Callable实例。它实际上是把Callable接口转化成了Runnable接口。
public class MachineTask implements Callable<Integer>{
@Override
public Integer call() {
int sum = 0;
for(int i = 0;i < 100;i++) {
sum += i;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return sum;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> task = new FutureTask<>(new MachineTask());
Thread thread = new Thread(task);
thread.start();
System.out.println("等待计算结果...");
Integer result = task.get();//主线程调用FutureTask的get()方法获取结果
System.out.println("结果为: " + result);
}
}