等待-唤醒模型的几种实现

1、wait-notify

1.0 就存在,最初始的实现方式。

wait()、notify()、notifyAll() 是 Object 类中的方法,所以使用范围是最广的,所有对象都可以使用这个方式再搭配 synchronized 关键字实现等待-唤醒模型。

缺点:1、nofity() 只能将调用当前对象的 wait() 方法的所有线程中的任意一个唤醒,不能做到精确唤醒

     2、wait()、notify()、notifyAll() 只能被用在 synchronized 作用的代码块中,否则就会抛出 illegalMonitorStateException 异常。

     3、notify()、notifyAll()方法作用后会立刻执行,将阻塞的某个(所有)线程唤醒,在执行后调用 wait() 方法后线程依然会阻塞,简而言之就是线程只能先 wait()进入阻塞后,才能被唤醒,如果线程的执行顺序改变导致先 notify 在 wait ,那么线程就会被一直阻塞,无法唤醒。

 

 

2、await-signal

Condition 是 1.5引入的类,它是为了优化 wait-notify 模型的。

await() 和 signal()、signalAll() 是 Condition 中的方法,而 Condition 对象可以通过 lock.newCondition 来创建。所以这个是配合 lock 锁使用的。相比于 wait-notify 模型,这种因为一个 lock 对象可以创建多个 Condition 对象,所以可以实现指定线程阻塞与唤醒

缺点:1、await()、signal()、signalAll() 同样只能被使用在 lock 锁锁定的代码块中,否则也会抛出 illegalMonitorStateException 异常。

      2、同样 await() 与 signal()、signalAll() 顺序不能变,否则就会造成无法唤醒。

 

 

3、LockSupport

LockSupport 是1.6 新引入的类,其中的 park()、unpark() 进一步优化了传统的 阻塞-唤醒模型。

LockSupport 的使用可以解决前面两个所有的缺点,可以在任何位置使用方法,不需要 try catch 修饰处理 illegalMonitorStateException 异常,它是使用 park() 阻塞当前线程,使用 unpark(Thread) 来唤醒指定线程,它的机制就和它的方法名一样,类似于停车位,有了停车卡才能停车,当先调用 park() 方法就相当于当前线程先进入停车场,但是因为没有停车卡所以只能阻塞等待分配停车卡;而先调用 unpark(Thread)则表示先给某个线程一张停车卡(每个线程最多只能拥有一张停车卡),当调用 park 就会消耗一张停车卡,而不会阻塞直接停好车,继续执行。

其内部使用的是 unsafe 类中的 native 方法,所以效率也较高。

 private static final sun.misc.Unsafe UNSAFE;


public static void park() {
        UNSAFE.park(false, 0L);
    }




public native void park(boolean var1, long var2);



public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }


public native void unpark(Object var1);

 

posted on 2020-11-22 17:21  萌新J  阅读(215)  评论(0编辑  收藏  举报