JAVA多线程学习与总结(四)
信号量Semaphore
Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
public void run() { try { // 获取许可 semp.acquire(); System.out.println("Accessing: " + NO); Thread.sleep((long) (Math.random() * 10000)); // 访问完后,释放 semp.release(); //availablePermits()指的是当前信号灯库中有多少个可以被使用 System.out.println("-----------------" + semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } }
关于生产者和消费者
/** * 仓库,用来存放产品 * * @author 林计钦 * @version 1.0 2013-7-24 下午04:54:16 */ public class Storage { BlockingQueue<Product> queues = new LinkedBlockingQueue<Product>(10);
主要是利用 这个阻塞队列来处理生产和消费。
信号变量
private Lock lock = new ReentrantLock(); // 账户锁 private Condition _save = lock.newCondition(); // 存款条件 private Condition _draw = lock.newCondition(); // 取款条件
通过 _save.signalAll()
_save.await();
而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。
主要这里,的lock实际上就是锁定到condition上面。
public void drawing(int x, String name) { lock.lock(); // 获取锁 try { if (cash - x < 0) { _draw.await(); // 阻塞取款操作 } else { cash -= x; // 取款 System.out.println(name + "取款" + x + ",当前余额为" + cash); } _save.signalAll(); // 唤醒所有存款操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); // 释放锁 } }
public void saving(int x, String name) { lock.lock(); // 获取锁 if (x > 0) { cash += x; // 存款 System.out.println(name + "存款" + x + ",当前余额为" + cash); } _draw.signalAll(); // 唤醒所有等待线程。 lock.unlock(); // 释放锁 }
可以看到 lock不会造成死锁。
障碍器
CountDownLatchu是所有子程序执行完以后,再执行主线程。关注的是主线程。
CyclicBarrier是多有子线程都执行到某一点后,在继续执行。关注的是子线程。
CyclicBarrierTest test = new CyclicBarrierTest(); // 创建障碍器,并设置MainTask为所有定数量的线程都达到障碍点时候所要执行的任务(Runnable) CyclicBarrier cb = new CyclicBarrier(7, test.new MainTask()); test.new SubTask("A", cb).start(); test.new SubTask("B", cb).start(); test.new SubTask("C", cb).start(); test.new SubTask("D", cb).start(); test.new SubTask("E", cb).start(); test.new SubTask("F", cb).start(); test.new SubTask("G", cb).start();
就是让所有子线程 执行到了
// 通知障碍器已经完成 cb.await();
然后才执行主线程。
这里是执行到了这个点,第一个是全部执行完毕。
这个可以用于 分表查询。
即所有的总数计算完毕,再执行主线程。
也可以通过join的方式,信号量,原子量方式。
还可以主线程中定时判断子线程执行结果。可以由线程队列,变量等得知具体情况。
还可以,主线程 await();
个人觉得还是join比较优雅。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。