内容摘要
这里主要介绍了java5中线程锁技术以外的其他同步工具,首先介绍Semaphore:一个计数信号量。用于控制同时访问资源的线程个数,CyclicBarrier同步辅助类:从字面意思看是路障,这里用于线程之间的相互等待,到达某点后,继续向下执行。CountDownLatch同步辅助类:在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。犹如倒计时计数器,然后是Exchanger:实现两个对象之间数据交换,可阻塞队列:ArrayBlockingQueue,通过阻塞队列间的通信来演示其作用,最后介绍了几个同步集合。
1. Semaphore实现信号灯
Semaphore可以维护当前访问自身的线程个数,并提供了同步机制,使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
Semaphore实现的功能就像:银行办理业务,一共有5个窗口,但一共有10个客户,一次性最多有5个客户可以进行办理,其他的人必须等候,当5个客户中的任何一个离开后,在等待的客户中有一个人可以进行业务办理。
Semaphore提供了两种规则:
- 一种是公平的:获得资源的先后,按照排队的先后。在构造函数中设置true实现
- 一种是野蛮的:谁有本事抢到资源,谁就可以获得资源的使用权。
与传统的互斥锁的异同:
单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁“,再由另外一个线程释放”锁“,这可以应用于死锁恢复的一些场合。
应用场景:共享资源的争夺,例如游戏中选手进入房间的情况。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
//创建一个可根据需要创建新线程的线程池
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3);
//创建10个线程
for(int i=0;i<10;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
sp.acquire(); //获取灯,即许可权
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"进入,当前已有" + (3-sp.availablePermits()) + "个并发");
try {
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"即将离开");
sp.release(); // 释放一个许可,将其返回给信号量
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (3-sp.availablePermits()) + "个并发");
}
};
service.execute(runnable);
}
}
}
输出结果
线程pool-1-thread-3进入,当前已有3个并发
线程pool-1-thread-2进入,当前已有3个并发
线程pool-1-thread-1进入,当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-2已离开,当前已有2个并发
线程pool-1-thread-5进入,当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-1已离开,当前已有2个并发
线程pool-1-thread-4进入,当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-4已离开,当前已有2个并发
线程pool-1-thread-8进入,当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-7进入,当前已有3个并发
线程pool-1-thread-3已离开,当前已有3个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-8已离开,当前已有2个并发
线程pool-1-thread-9进入,当前已有3个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开,当前已有2个并发
线程pool-1-thread-6进入,当前已有3个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-9已离开,当前已有2个并发
线程pool-1-thread-10进入,当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-5已离开,当前已有2个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-6已离开,当前已有1个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开,当前已有0个并发
控制一个方法的并发量,比如同时只能有3个线程进来
public class ThreadPoolTest {
//信号量
private static Semaphore semaphore = new Semaphore(3);//允许个数,相当于放了3把锁
public static void main(String[] args) {
for(int i=0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
method();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
//同时最多只允许3个线程过来
public static void method() throws InterruptedException{