首页 > 技术文章 > JUC_01 线程阻塞、唤醒三种方式

yuefeng123 2021-05-10 11:07 原文

三种方式总结:

一、synchronized: wait、notify、notifyAll
      1、需要结合synchronized使用,否作会出现异常
      2、必须先执行wait, 后执行notify或者notifyAll,否作会一直处于阻塞状态           
二、Lock.condition:  await、signal、signalAll
      1、需要结合lock使用,否作会出现异常
      2、必须先执行await, 后执行signal或者signalAll, 否作会一直处于阻塞状态
三、LockSupport: park、unpark
      1、不依赖其它外部代码
      2、park、unpark执行没有先后顺序
      3、unpark方法同一时间最多只能获取一个许可证,只能通知一个park方法

 

package com.scwyfy.knowledge.juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * LockSupport:park()与unpark() 用来阻塞和唤醒线程,不需要手动加锁即可实现,且对阻塞、唤醒顺序无要求
 *              注意: 执行多次unpark(),最多也只能获取一个许可证(不会进行累加操作),只能唤醒一个park()
 *              例如:先执行两次unpark(),再执行两次park(), 第二个park()将会处于阻塞状态
 * Synchronized: wait()与notify()或者notifyAll 用于阻塞和唤醒线程,需要结合Synchronized一起使用,否则将会产生异常 IllegalMonitorStateException
 *               且必须先wait(),再notify()。不然将会一直处于阻塞状态
 * Lock
 *  Condition: await()与signal()或者signalAll 用于阻塞和唤醒线程,需要结合Lock一起使用,否则将会产生异常 IllegalMonitorStateException
 *               且必须先await(),再signal()。不然将会一直处于阻塞状态
 */
public class LockSupportDemo {



    public static void main(String[] args) {
//        synchronizedSolution();
//        lockSolution();
//        lockSupportSolution();
        parkAndUnparkDemo();

    }

    /**
     * unpark方法:许可证最多只能有一个
     */
    private static void parkAndUnparkDemo() {
        Thread thread = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3L);// 目的先让执行unpark方法
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("准备执行两次park方法");
            LockSupport.park();
            System.out.println("已执行一次park方法");
            LockSupport.park();
            System.out.println("park方法执行完成");
        });
        thread.start();
        new Thread(() -> {
            System.out.println("准备执行两次unpark方法");
            LockSupport.unpark(thread);
            LockSupport.unpark(thread);
            System.out.println("unpark方法执行完成");
        }).start();
    }

    /**
     * LockSupport方式实现 阻塞、唤醒
     */
    private static void lockSupportSolution() {
        Thread a = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3L);
                System.out.println(Thread.currentThread().getName() + " --- 进入");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LockSupport.park(); // 不需要依赖外部代码,park与unpark方法不用区分先后执行顺序
            System.out.println(Thread.currentThread().getName() + " --- 出来");
        }, "a");
        a.start();

        Thread b = new Thread(() -> {
            LockSupport.unpark(a); // 不需要依赖外部代码,park与unpark方法不用区分先后执行顺序
            System.out.println(Thread.currentThread().getName() + " --- 通知");
        }, "b");
        b.start();
    }

    /**
     * Lock.Condition方式实现阻塞、唤醒
     */
    private static void lockSolution() {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() -> {
            try {
//                TimeUnit.SECONDS.sleep(3L);// 先signal,再await,会一直处于阻塞状态
                lock.lock();
                System.out.println(Thread.currentThread().getName() + " --- 进入");
                condition.await(); // 不结合lock,await、signal方法会有异常IllegalMonitorStateException
                System.out.println(Thread.currentThread().getName() + " --- 出来");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + " --- 通知");
                condition.signal();
            } finally {
                lock.unlock();
            }
        }, "B").start();
    }

    /**
     * synchronized方式实现阻塞、唤醒
     */
    private static void synchronizedSolution() {
        Object synchronizedLock = new Object();
        new Thread(() -> {
            try {
//                TimeUnit.SECONDS.sleep(3L); // 先notify,再wait。会一直阻塞状态
                synchronized (synchronizedLock) {// 不结合synchronized, wait、notify方法会有异常IllegalMonitorStateException
                    System.out.println(Thread.currentThread().getName() + " --- 进入");
                    synchronizedLock.wait();
                    System.out.println(Thread.currentThread().getName() + " --- 出来");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
           synchronized(synchronizedLock) {
               synchronizedLock.notify();
               System.out.println(Thread.currentThread().getName() + " --- 通知");
           }
        }, "B").start();
    }

}

 

推荐阅读