Semaphore
信号量控制一起进入线程的数量,通俗点讲是 synchronized 的加强版,作用是控制线程的并发数量
final Semaphore sh = new Semaphore(2);//信号量为2
for(int i = 0; i < 3; i++) {
Thread t=new Thread(new Runnable() {
public void run() {
try {
sh.acquire(); //获取信号量
for(int i = 0; i< 10; i++) {
System.out.println("执行的线程"+Thread.currentThread().getName()+"循环第"+i+"次");
}
Thread.sleep(5000); //一个线程休眠5s
sh.release(); //释放信号量
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.start();
}
这三个线程只有两个能同时执行,第三个线程需要在前两线程有一个结束后5s后才能执行,执行的标准是信号量是否为0,
CountDownlatch
一个任务等待一组任务,结束后,被唤醒的功能
注意:直到由于 countDown() 方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await 调用立即返回。 这是一个一次性的现象 - 计数无法重置。 如果您需要重置计数的版本,请考虑使用CyclicBarrier 。 .
(1)首先示例正常多个线程全部完成再执行下面的
final static CountDownLatch ctl = new CountDownLatch(10);
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newFixedThreadPool(2);
for (int i=0; i<10; i++){
Thread t=new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i< 10; i++) {
System.out.println("执行的线程"+Thread.currentThread().getName()+"循环第"+i+"次");
}
Thread.sleep(1000);
ctl.countDown();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
exec.submit(t);
}
// 等待检查
ctl.await();
// 需要等待的所有线程执行完毕,可以继续往下执行
System.out.println("需要等待的所有线程结束");
// 关闭线程池
exec.shutdown();
}
(2) 一个倒计时器循环多线程
final static CountDownLatch ctl = new CountDownLatch(10);
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newFixedThreadPool(2);
for(int j = 0;j<2;j++) {
for (int i=0; i<10; i++){
Thread t=new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i< 10; i++) {
System.out.println("执行的线程"+Thread.currentThread().getName()+"循环第"+i+"次");
}
Thread.sleep(1000);
ctl.countDown();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
exec.submit(t);
}
// 等待检查
ctl.await();
// 需要等待的所有线程执行完毕,可以继续往下执行
System.out.println("需要等待的所有线程执行完毕,可以执行下面的程序!");
}
// 关闭线程池
exec.shutdown();
}
出现问题了,第二个多线程没等全部的线程结束就执行了
所以:CountDownLatch 在数值减为0后不重置,一锤子买卖
CycliBarrier
一组线程彼此互相等待
final static CyclicBarrier cb = new CyclicBarrier(5); //屏障线程的数量为5
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newFixedThreadPool(5);//线程池
for (int i=0; i<5; i++){
Thread t=new Thread(new Runnable() {
public void run() {
try {
System.out.println("执行的线程"+Thread.currentThread().getName()+"到达屏障");
System.out.println("线程"+Thread.currentThread().getName()+"等待其他线程到达屏障");
Thread.sleep(1000);
cb.await(); //到达屏障
System.out.println(Thread.currentThread().getName()+"冲破屏障");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
exec.submit(t);
}
// 关闭线程池
exec.shutdown();
}
结果
当然可以重置(可以主动reset(),也可以被动 ),不像CountDownlatch 不能重置
比较CountDownlatch和CycliBarrier
- CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
- CountDownLatch 参与的线程的目的是不一样的,有的在倒计时,有的在等待倒计时结束,CyclicBarrier 参与的线程的目的是一样的