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比较优雅。
 
 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。