◆
CountDownLatch
◆
假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以。
比如你想要买套房子,但是呢你现在手上没有钱。你得等这个月工资发了、然后年终奖发了、然后朋友借你得钱还给你了、然后再给朋友借一部分才可以买,这种场景你就可以使用CountDownLatch。
CountDownLatch是JDK为我们提供的一个计数器,它的操作是原子操作,同一时间只能有一个线程去操作这个它。
我们先来看一下CountDownLatch的主要方法。
下面是CountDownLatch的基本使用示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class CountDownLatchDemo { public static CountDownLatch countDownLatch = new CountDownLatch(5); static class ThreadDemo extends Thread { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getId() + "完成任务"); countDownLatch.countDown(); } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 5; i++) { new ThreadDemo().start(); } countDownLatch.await(); System.out.println("全部完成任务"); } }
|
◆
CyclicBarrier
◆
相比较于CountDownLatch,CyclicBarrier可以完成前者的全部功能,但是相比前者,它的功能更加的强大。
CyclicBarrier翻译过来的中文名称叫循环栅栏,顾名思义它可以循环使用
CyclicBarrier还可以接收一个Runnable对象,当栅栏循环一次技术后会执行一次Runnable
我们来看一下CyclicBarrier的常用方法:
下面是CyclicBarrier的基本使用示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
public class CyclicBarrierDemo { public static CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new FinallyThreadDemo()); static class ThreadDemo extends Thread { @Override public void run() { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getId() + "完成任务"); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("到达屏障点每个线程都会瞬时继续执行"); } } static class FinallyThreadDemo extends Thread { @Override public void run() { System.out.println("所有任务已经完成之后单独执行的任务!"); } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10; i++) { new ThreadDemo().start(); } } }
|
观察打印结果我们可以发现:
当循环栅栏的任务执行完一轮以后,如果构造时传入了Runnable对象,则先执行Runnable对象,然后在瞬间释放所有任务的锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
14完成任务 15完成任务 16完成任务 17完成任务 18完成任务 所有任务已经完成之后单独执行的任务! 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 19完成任务 20完成任务 21完成任务 22完成任务 23完成任务 所有任务已经完成之后单独执行的任务! 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行 到达屏障点每个线程都会瞬时继续执行
|
◆
Semaphore
◆
在 浅谈Java中的锁:Synchronized、重入锁、读写锁 一文中,我们了解了synch和读写锁,我们发现使用锁的时候一次只允许一条线程方法。那么有什么东西可以提供更强大的控制方法么?这个东西就是信号量。
信号量提供的主要方法:
下面来看使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public class SemaphoreThreadDemo { public static Semaphore semaphore = new Semaphore(5);
static class ThreadDemo extends Thread { @Override public void run() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getId() + "号线程在"+System.currentTimeMillis()+"获取资源"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); } } }
public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 30; i++) { new ThreadDemo().start(); } }
}
|
◆
LockSupport
◆
我们在 Hello,Thread 和 生产者消费者模型 两篇文章中使用过wait和notify实现了线程之间的协作,其实关于线程协作JDK还为我们提供了另外一个工具类LockSupport。
使用LockSupport实现等待通知功能时还不需要获取锁哦
先来看一下LockSupport的常用方法:
来看一下示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
public class LockSupportThreadDemo { public static Thread thread; static class WaitThreadDemo extends Thread { @Override public void run() { System.out.println("WaitThread wait,time=" + System.currentTimeMillis()); thread = Thread.currentThread(); LockSupport.park(); System.out.println("WaitThread end,time=" + System.currentTimeMillis()); } } static class NotifyThreadDemo extends Thread { @Override public void run() { System.out.println("NotifyThread notify,time=" + System.currentTimeMillis()); LockSupport.unpark(thread); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("NotifyThread end,time=" + System.currentTimeMillis()); } } public static void main(String[] args) { WaitThreadDemo waitThreadDemo = new WaitThreadDemo(); NotifyThreadDemo notifyThreadDemo = new NotifyThreadDemo(); waitThreadDemo.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } notifyThreadDemo.start(); } }
|