LockSupport类里面的park()和unpark()多次调用

LockSupport类里面的park()和unpark()多次调用

多次调用unpark方法和调用一次unpark方法效果一样,因为在源码里面都是直接将_counter赋值为1,而不是加1。简单说就是:线程A连续调用两次LockSupport.unpark(B)方法唤醒线程B,然后线程B调用两次LockSupport.park()方法, 线程B依旧会被阻塞。因为两次unpark调用效果跟一次调用一样,只能让线程B的第一次调用park方法不被阻塞,第二次调用依旧会阻塞。

证明上面的观点,首先是直接调用两次LockSupport.unpark(),然后在调用两次LockSupport.park()之后是被阻塞的,比如下面的代码,首先main主线程就会被执行两次LockSupport.unpark(),然后main线程再执行两次LockSupport.park(),这样的结果很明显就是最终被阻塞了,原因就是上面的原因

package com.one.domain;

import java.util.concurrent.locks.LockSupport;

/**
 * @Author: wb-mqk568853
 * @Date: 2019/6/17 20:39
 */
public class Hello {

    private static Thread mainThread;

    public static void main(String[] args) {

        ThreadA zi = new ThreadA("zi");
        // 获取主线程
        mainThread = Thread.currentThread();

        zi.start();
        // 主线程阻塞
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (Hello.class){
            System.out.println("main线程第一次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }
        synchronized (Hello.class){
            System.out.println("main线程第二次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }

        System.out.println(Thread.currentThread().getName() + " continue");
    }

    static class ThreadA extends Thread {

        public ThreadA(String name) {
            super(name);
        }

        @Override
        public void run() {
            // 唤醒“主线程”
            synchronized (this){
                System.out.println("main线程第一次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }

            synchronized (this){
                System.out.println("main线程第二次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }

        }

    }
}

LockSupport类里面的park()和unpark()多次调用_第1张图片
那么上面的代码怎么让unpark和park进行替换调用呢,就是达到不阻塞的结果,这个很简单,就像下面这样做就好了,下面的for循环就是进行测试的,就是测试10000次结果是否一样,至于下面为什么要睡眠,并且睡眠1毫秒呢,下面讲一下

package com.one.domain;

import java.util.concurrent.locks.LockSupport;

/**
 * @Author: wb-mqk568853
 * @Date: 2019/6/17 20:39
 */
public class Second {

    private static Thread mainThread;

    public static void main(String[] args) {
        for(int i=0;i<10000;i++){
            System.out.println(i);
            cc();
        }
    }


    public static void cc() {

        ThreadA zi = new ThreadA("zi");

        mainThread = Thread.currentThread();

        zi.start();
        synchronized (Second.class){
            System.out.println("main线程第一次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }
        synchronized (Second.class){
            System.out.println("main线程第二次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }
    }

    static class ThreadA extends Thread {

        public ThreadA(String name) {
            super(name);
        }

        @Override
        public void run() {
            synchronized (this){
                System.out.println("main线程第一次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this){
                System.out.println("main线程第二次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }

        }

    }
}

LockSupport类里面的park()和unpark()多次调用_第2张图片

为什么要加上面的睡眠呢,我们看一下不加有什么问题,

package com.one.domain;

import java.util.concurrent.locks.LockSupport;

/**
 * @Author: wb-mqk568853
 * @Date: 2019/6/17 20:39
 */
public class Second {

    private static Thread mainThread;

    public static void main(String[] args) {
        for(int i=0;i<10000;i++){
            System.out.println(i);
            cc();
        }
    }


    public static void cc() {

        ThreadA zi = new ThreadA("zi");

        mainThread = Thread.currentThread();

        zi.start();
        synchronized (Second.class){
            System.out.println("main线程第一次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }
        synchronized (Second.class){
            System.out.println("main线程第二次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }
    }

    static class ThreadA extends Thread {

        public ThreadA(String name) {
            super(name);
        }

        @Override
        public void run() {
            synchronized (this){
                System.out.println("main线程第一次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }
           /* try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
            synchronized (this){
                System.out.println("main线程第二次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }

        }

    }
}

此时可以看到第六次执行的时候,就出现了问题了,这是因为unpark()两次执行的效果是一样的,也就是说第一次的park()被第二次和第三次的unpark()给取消了,然后第四次你有进行了unpark,所以此时就阻塞了,为什么会出现下面的原因呢,这是因为子线程执行的快,他一下子把上面的绿色代码里面的unpark()都执行完毕了,所以就会出现下面的结果,这就是上面我为什么要给子线程进行睡眠的原因
LockSupport类里面的park()和unpark()多次调用_第3张图片

park和unpark的灵活之处

在Java5里是用wait/notify/notifyAll来同步的。wait/notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。这样就很麻烦了,

但是使用park和unpark的好处,他不需要关心park和unpark的调用顺序,就是一个线程它有可能在别的线程unPark之前,或者之后,或者同时调用了park,这样都是没有问题的

那么怎么实现park()和unpark():首先是unpark()放到park()前面,这个如下所示

public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        LockSupport.unpark(thread);
        System.out.println("1.");
        LockSupport.park(thread);
        System.out.println("2.");
    }

LockSupport类里面的park()和unpark()多次调用_第4张图片

然后把park()放到unpark()的前面进行调用,下面的代码就是对主线程先park(),然后在进行unpark()

package com.one.domain;

import java.util.concurrent.locks.LockSupport;

/**
 * @Author: wb-mqk568853
 * @Date: 2019/6/17 20:39
 */
public class Second {

    private static Thread mainThread;

    public static void main(String[] args) {
        ThreadA zi = new ThreadA("zi");

        mainThread = Thread.currentThread();

        zi.start();

        synchronized (Second.class){
            System.out.println("main线程第一次调用 LockSupport.park");
            LockSupport.park(mainThread);
        }
    }

    static class ThreadA extends Thread {

        public ThreadA(String name) {
            super(name);
        }

        @Override
        public void run() {
            synchronized (this){
                System.out.println("main线程第一次调用 LockSupport.unpark");
                LockSupport.unpark(mainThread);
            }

        }

    }
}

LockSupport类里面的park()和unpark()多次调用_第5张图片

能看到这里的同学,就帮忙右上角点个赞吧,Thanks♪(・ω・)ノ

你可能感兴趣的:(#,Java类,Java)