一,Semphore的使用
信号量主要有两个作用,一个是用于多个共享资源的互斥使用,另一个用于并发线程数控制。
(1)通过acquire()获取一个信号量,计数器减一,信号量为0,线程进入阻塞等待状态。
(2)通过realease()释放一个信号量,计数器加一,如果有等待的线程则唤醒。
(3)实战
public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 获取到了"); try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } }).start(); }
}
//运行结果
Thread-0 获取到了
Thread-1 获取到了
Thread-2 获取到了
Thread-1
Thread-2
Thread-3 获取到了
Thread-0
Thread-4 获取到了
Thread-3 // 这两个线程获取信号量的时候为0,所以需要等其他线程执行完毕才会执行
Thread-4 //
二,CountDownLatch的使用
当计数器的值为0时,调用await()方法的线程才会被唤醒,继续往下执行。可用于控制让一个线程在指定线程数的线程执行完毕之后接着执行。
(1)countDown()方法调用之后,计数器减一,最小为0。
(2)await()被调用之后,线程阻塞直到计数器的值为0。
(3)实战
public static void main(String[] args) { CountDownLatch countDownLatch = new CountDownLatch(3); for (int i = 0; i < 4; i++) { new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); } }).start(); } try { countDownLatch.await(); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }
//运行结果
Thread-0
Thread-1
Thread-2
Thread-3
2
1
0
main //当三个线程执行完毕之后,main才会执行;并且计数器的值最小是为0
0
三,CyclicBarrier的使用
所有的线程都到达await()方法之后, 统一往下执行。
(1)await()方法线程阻塞,计数器为0,开始运行。
(2)reset()方法重置计数器的值
(3)实战
public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(3); for (int i = 0; i <3 ; i++) { new Thread(new Runnable() { @Override public void run() { try { System.out.println(Thread.currentThread().getName()+" 到达状态"); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ " 开始执行"); } }).start(); } }
//运行结果
Thread-0 到达状态
Thread-1 到达状态
Thread-2 到达状态
Thread-0 开始执行
Thread-2 开始执行
Thread-1 开始执行
(4)CyclicBarrier和CountDownLatch的区别
CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的;CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。