并发-CountDownLatch、 CyclicBarrier、Semaphore

CountDownLatch

1.测试案例

package cn.zwc.demo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 
 * @author zwc
 * @date 2018年12月4日 下午7:53:24
 */
public class CountDownLatchDemo01 {
	public static void main(String[] args) {
		final CountDownLatch latch = new CountDownLatch(4);// 创建框架
		for(int i = 0; i < 4; i++){
			Thread threa = new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName()+"\t正在执行中!");
					try {
						TimeUnit.SECONDS.sleep(3);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"\t执行完毕!");
					latch.countDown(); // 框架计数器-1
				}
			},"task"+i);
			threa.start();
		}
		System.out.println("4个线程正在执行");
		// 唤醒等待
		try {
			latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main Thread.......");
	}
}

执行结果

4个线程正在执行
task2	正在执行中!
task1	正在执行中!
task3	正在执行中!
task0	正在执行中!
task1	执行完毕!
task3	执行完毕!
task2	执行完毕!
task0	执行完毕!
main Thread.......

如果latch.await();注释掉这一段的话,执行结果是
错误的示范
从以上的结果分析,latch.await(); 只有等所有的线程执行完毕,才会执行其他的线程(main线程)
如果没有的话,主线程可能先于多线程执行完毕

2.源码解读

  • 构造函数
   public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
  • 执行计数
// CountDownLatch中的
 public void countDown() {
        sync.releaseShared(1);
    }

调用的  releaseShared 是 AbstractQueuedSynchronizer.中的
  public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

tryReleaseShared 是 CountDownLatch中的内部类   Sync 中
    protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }

doReleaseShared 是 AbstractQueuedSynchronizer的方法
    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

CyclicBarrier

1.测试案例

package cn.zwc.demo;

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
		for (int i = 0; i < 5; i++) {
			Write write = new Write(cyclicBarrier);
			write.start();
		}
		System.out.println("主线程执行完毕");
	}

	static class Write extends Thread {
		private CyclicBarrier cyclicBarrier;

		public Write(CyclicBarrier cyclicBarrier) {
			this.cyclicBarrier = cyclicBarrier;
		}

		@Override
		public void run() {
			System.out.println("线程" + Thread.currentThread().getName() + ",正在写入数据");
			try {
				Thread.sleep(3000);
			} catch (Exception e) {
			}
			System.out.println("线程" + Thread.currentThread().getName() + ",写入数据成功.....");
			try {
				cyclicBarrier.await();
			} catch (Exception e) {
			}
			System.out.println("所有线程执行完毕..........");
		}
	}
}

执行结果:

主线程执行完毕
线程Thread-3,正在写入数据
线程Thread-0,正在写入数据
线程Thread-2,正在写入数据
线程Thread-1,正在写入数据
线程Thread-4,正在写入数据
线程Thread-0,写入数据成功.....
线程Thread-3,写入数据成功.....
线程Thread-2,写入数据成功.....
线程Thread-4,写入数据成功.....
线程Thread-1,写入数据成功.....
所有线程执行完毕..........
所有线程执行完毕..........
所有线程执行完毕..........
所有线程执行完毕..........
所有线程执行完毕..........

只有等待所有线程执行完成,才能执行之后的主线程

2.源码阅读

// 
  public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen;
        }
    }
/**
     * Main barrier code, covering the various policies.
     */
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
            final Generation g = generation;
			// 判断当前线程是否是broken
            if (g.broken)
                throw new BrokenBarrierException();
			// 判断当前线程是否被中断,如果被中断,调用 trip.signalAll();将会唤醒所有等待的线程
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

           int index = --count;
           if (index == 0) {  // tripped
               boolean ranAction = false;
               try {
                   final Runnable command = barrierCommand;
                   if (command != null)
                       command.run();
                   ranAction = true;
                   nextGeneration();
                   return 0;
               } finally {
                   if (!ranAction)
                       breakBarrier();
               }
           }

            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
        // 释放锁
            lock.unlock();
        }
    }

Semaphore

1.测试案例

Semaphore 顾名思义,表示的是信号量,以下案例表示的是5个资源,同时只能2个竞争资源

package cn.zwc.demo;

import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 * 10个人抢三个资源的问题
 * @author zwc
 * @date 2018年8月2日 下午4:17:53
 */
public class SemaphoreTest {
	public static void main(String[] args) {
		Semaphore semaphore = new Semaphore(2);
		for(int i = 1; i <= 5; i++){
			Parent parent = new Parent("第"+ i +"个人", semaphore);
			new Thread(parent).start();
		}
	}
	
	static class Parent implements Runnable{
		private String name;
		private Semaphore wc;
		
		public Parent(String name,Semaphore wc) {
			this.name = name;
			this.wc = wc;
		}

		@Override
		public void run() {
			try{
//				int availablePermits = wc.availablePermits();
				// 申请茅坑,如果资源到达三次,就等待
//				if(availablePermits > 0){
//					System.out.println(name+"天助我也,居然有座位");
//				} else {
//					System.out.println(name+"哎呀~,为啥没有座位了呢?");
//				}
				wc.acquire();
				System.out.println(name+"我可以准备吃饭了。。。");
				Thread.sleep(new Random().nextInt(1000));
				System.out.println(name + "我吃完了呀");
				wc.release();
				System.out.println(name + "------释放了锁");
			}catch(Exception e){
			}
		}
	}
}

2.结果显示:

第1个人我可以准备吃饭了。。。
第2个人我可以准备吃饭了。。。
第1个人我吃完了呀
第1个人------释放了锁
第3个人我可以准备吃饭了。。。
第3个人我吃完了呀
第3个人------释放了锁
第5个人我可以准备吃饭了。。。
第2个人我吃完了呀
第2个人------释放了锁
第4个人我可以准备吃饭了。。。
第4个人我吃完了呀
第4个人------释放了锁
第5个人我吃完了呀
第5个人------释放了锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值