• Java多线程--让主线程等待子线程执行完毕


    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待。

    java.util.concurrent.CountDownLatch

    使用countDownLatch.await()方法非常简单的完成主线程的等待:

    public class ThreadWait {
    
        public static void main(String[] args) throws InterruptedException {
            int threadNumber = 10;
            final CountDownLatch countDownLatch = new CountDownLatch(threadNumber);
            for (int i = 0; i < threadNumber; i++) {
                final int threadID = i;
                new Thread() {
                    public void run() {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(String.format("threadID:[%s] finished!!", threadID));
                        countDownLatch.countDown();
                    }
                }.start();
            }
    
            countDownLatch.await();
            System.out.println("main thread finished!!");
        }
    }

    CountDownLatch源码解析:

    1.先看看await()方法:

        public void await() throws InterruptedException {
            sync.acquireSharedInterruptibly(1);
        }
    
        public final void acquireSharedInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (tryAcquireShared(arg) < 0)
                doAcquireSharedInterruptibly(arg);
        }
    
        private void doAcquireSharedInterruptibly(int arg)
            throws InterruptedException {
            final Node node = addWaiter(Node.SHARED);
            boolean failed = true;
            try {
                for (;;) {
                    final Node p = node.predecessor();
                    if (p == head) {
                        int r = tryAcquireShared(arg);
                        if (r >= 0) {
                            setHeadAndPropagate(node, r);
                            p.next = null; // help GC
                            failed = false;
                            return;
                        }
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }

    主要看parkAndCheckInterrupt()方法,就是是如何将主线程阻塞住的方法:

        private final boolean parkAndCheckInterrupt() {
            LockSupport.park(this);    //通过LockSupport.park()方法将线程交给系统阻塞;
            return Thread.interrupted();
        }

    2.看看countDown()方法,我们看看最终被countDown调用的unparkSuccessor()方法;

        private void unparkSuccessor(Node node) {
            /*
             * If status is negative (i.e., possibly needing signal) try
             * to clear in anticipation of signalling.  It is OK if this
             * fails or if status is changed by waiting thread.
             */
            int ws = node.waitStatus;
            if (ws < 0)
                compareAndSetWaitStatus(node, ws, 0);
    
            /*
             * Thread to unpark is held in successor, which is normally
             * just the next node.  But if cancelled or apparently null,
             * traverse backwards from tail to find the actual
             * non-cancelled successor.
             */
            Node s = node.next;
            if (s == null || s.waitStatus > 0) {
                s = null;
                for (Node t = tail; t != null && t != node; t = t.prev)
                    if (t.waitStatus <= 0)
                        s = t;
            }
            if (s != null)
                LockSupport.unpark(s.thread);
        }

    我们可以看到最终使用LockSupport.unpark()方法唤醒了主线程。

    注:LockSupport类中的park与unpark方法都是使用的unsafe中的native本地方法;

    最后我们来看一段最简单的使用park与unpark方法阻塞唤醒线程代码:

        public static void main(String[] args) {
    
            Thread t = new Thread(() -> {
                System.out.println("阻塞线程1");
                LockSupport.park();
                System.out.println("线程1执行完啦");
            });
    
            t.start();
    
            try {
                Thread.sleep(2000);
                System.out.println("唤醒线程1");
                LockSupport.unpark(t);
                Thread.sleep(2000);
                System.out.println("主线程结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }

    运行结果:

    阻塞线程1
    唤醒线程1
    线程1执行完啦
    主线程结束
  • 相关阅读:
    python基础:内置函数zip,map,filter
    python基础:网络编程
    python基础:异常捕捉
    jQuery demo
    day14 jQuery
    day13 JS Dom
    页面垂直方向出现两个滚动条问题?
    修复npm ERR! cb()never called!的错误;This is an error with npm itself. Please report this error at:
    vue——解决“You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file. ” eslint报错,取消文件的rules
    原型链
  • 原文地址:https://www.cnblogs.com/eoss/p/5902939.html
Copyright © 2020-2023  润新知