闭锁:CountDownLatch
使用场景
当前线程需要等待若干条线程执行完毕后,才能继续执行的情况。
也可以是若干个步骤执行完毕后的情况。
使用方法
初始化闭锁的时候,填入计数值,然后等待其他线程或者步骤对计数值进行操作减减。当计数值变为0的时候,线程就会从闭锁的await()方法处继续执行。
不能将计数值的参数设置为0,因为这样就毫无意义。
使用示例
// 初始化闭锁,并设置资源个数
CountDownLatch c = new CountDownLatch(2);
Thread t1 = new Thread( new Runnable(){
public void run(){
// 加载资源1
loadSomething();
// 本资源加载完后,计数值-1
c.countDown();
}
} ).start();
Thread t2 = new Thread( new Runnable(){
public void run(){
// 加载资源2
loadSomething();
// 本资源加载完后,计数值-1
c.countDown();
}
} ).start();
Thread t3 = new Thread( new Runnable(){
public void run(){
// 线程阻塞,等待计数值为0
c.await();
// 当闭锁计数值为0时,await返回,执行接下来的任务
dosomething();
}
} ).start();
同步屏障:CyclicBarrier
作用
让一组线程中的每一个线程达到一个位置的时候被阻塞,直到最后一个线程到达屏障,所有被阻塞的线程继续运行。
与闭锁的区别
- 闭锁只能阻塞一个线程,目的是为了让当个线程满足某种条件。
- 同步屏障可以满足多个线程同时阻塞,并同时继续执行。
使用方法
在实例化同步屏障的时候,填入线程等待个数,当等待的线程数满足这个数值要求,同步屏障才会释放。
使用示例
// 实例化对象,填入需要等待的线程数和屏障开启的任务
CyclicBarrier barrier = new CyclicBarrier(10, new Runnable(){
public void run(){
//当所有线程准备完毕后触发此任务
}
});
// 启动10条线程
for( int i=0; i < 10; i++ ) {
new Thread( new Runnable() {
public void run() {
// 等待,(同步屏障数量-1,直到为0时,打开屏障)
barrier.await();
dosomething();
}
} ).start();
}
信号量:
作用
可以控制访问特定资源的线程数量。
使用方法
示例化对象的时候,填入最大可访问的线程数量。在获取资源之前,调用acquire,获取完毕之后,调用release。
使用示例
// 实例化信号量对象,设置最大访问线程参数为5
Semaphore semaphore = new Semaphore(5);
// 启动 10条线程
for ( int i=0; i < 10; i++ ) {
new Thread( new Runnbale(){
public void run(){
// 获取资源,若此时资源数值为0,则阻塞,当资源数大于0,则继续执行
semaphore.acquire();
// 任务代码
soSomething();
// 释放资源
semaphore.release();
}
} ).start();
}