CountDownLatch闭锁

1、join

我们需要解析一个Excel里多个sheet的数据,此时可以考虑使用多 线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完 成。在这个需求中,要实现主线程等待所有线程完成sheet的解析操作,最简单的做法是使用 join()方法

public class JoinCountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                 System.out.println("parser1 finish");
            }
        });
        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("parser2 finish");
            }
        });
        parser1.start();
        parser2.start();
        parser1.join();
        parser2.join();
        System.out.println("all parser finish");
    }
}

join用于让当前执行线程等待join线程执行结束。其实现原理是不停检查join线程是否存 活,如果join线程存活则让当前线程永远等待。其中,wait(0)表示永远等待下去

public final void join() throws InterruptedException {
	join(0);
}

public final synchronized void join(long millis) throws InterruptedException {
	long base = System.currentTimeMillis();
	long now = 0;

	if (millis < 0) {
		throw new IllegalArgumentException("timeout value is negative");
	}

	if (millis == 0) {
		while (isAlive()) {
			wait(0);
		}
	} else {
		while (isAlive()) {
			long delay = millis - now;
			if (delay <= 0) {
				break;
			}
			wait(delay);
			now = System.currentTimeMillis() - base;
		}
	}
}

2、CountDownLatch

JDK 1.5之后的并发包中提供的CountDownLatch代替join的功能

public class JoinCountDownLatchTest  {
    static CountDownLatch c = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
	
	
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                 System.out.println("parser1 finish");
                //N--
                c.countDown();
            }
        });
        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("parser2 finish");
                //N--
                c.countDown();
            }
        });
        parser1.start();
        parser2.start();
        //阻塞当前线程,直到N变成零
        c.await();
        System.out.println("all parser finish");
    }
}

3、CountDownLatch原理:

创建CountDownLatch时需要传入一个计数N。

当我们调用CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await方法会阻塞当前线程,直到N变成零。

由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤

如果有某个解析sheet的线程处理得比较慢,我们不可能让主线程一直等待,所以可以使
用另外一个带指定时间的await方法——await(long time,TimeUnit unit),这个方法等待特定时
间后,就会不再阻塞当前线程。join也有类似的方法。

注意:计数器必须大于等于0,否则await方法时不会阻塞当前线程。
而且CountDownLatch不能重新初始化或者修改CountDownLatch对象的内部计数器的值。这也是他比同步屏障CyclicBarrier弱的地方

CountDownLatch的内部类Sync,继承自AQS


public class CountDownLatch {

    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            //循环进行CAS,直到当前线程成功完成CAS使计数值减一并更新到state
            for (;;) {
                int c = getState();
				//如果当前状态值为0则直接返回
                if (c == 0)
                    return false;
                int nextc = c-1;
				//CAS设置计数值减一
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;


    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }


    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }


    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }


    public void countDown() {
        sync.releaseShared(1);
    }


    public long getCount() {
        return sync.getCount();
    }

    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值