monitor&wait notify&join原理

 Monitor 原理

        Monitor 被翻译为监视器或管程。
        每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的Mark Word 中就被设置指向 Monitor 对象的指针。
        Monitor 结构如下。

         ● 刚开始 Monitor 中 Owner 为 null。
         ● 当 Thread-2 执行 synchronized(obj) 就会将 Monitor 的所有者 Owner 置为 Thread-2,Monitor中只能有一个 Owner。
         ● 在 Thread-2 上锁的过程中,如果 Thread-3,Thread-4,Thread-5 也来执行 synchronized(obj),就会进入EntryList BLOCKED。
         ● Thread-2 执行完同步代码块的内容,然后唤醒 EntryList 中等待的线程来竞争锁,竞争的时是非公平的。
         ● 图中 WaitSet 中的 Thread-0,Thread-1 是之前获得过锁,但条件不满足进入 WAITING 状态的线程,后面讲wait-notify 时会分析 

注意:
synchronized 必须是进入同一个对象的 monitor 才有上述的效果
不加 synchronized 的对象不会关联监视器,不遵从以上规则

wait notify 原理

         ● Owner 线程发现条件不满足,调用被上锁对象的wait 方法,即可进入 WaitSet 变为 WAITING 状态
         ● BLOCKED 和 WAITING 的线程都处于阻塞状态,不占用 CPU 时间片
         ● BLOCKED 线程会在 Owner 线程释放锁时唤醒
         ● WAITING 线程会在 Owner 线程调用 notify 或 notifyAll 时唤醒,但唤醒后并不意味者立刻获得锁,仍需进入
         ● EntryList 重新竞争

join原理

作用:等待线程执行结束。是调用者轮询检查线程 alive 状态。

        以下例子中,t1睡10秒,执行到t1.wait(0),即使主线程已放弃t1对象的monitor,但是synchronized代码块还未执行完,主线程就不能执行下去。直到while循环结束,即t1线程已执行完毕,死亡。synchronized代码块执行完毕,主线程继续向下执行。

        t1线程执行完毕后好像还会唤醒主线程,这个说法有待商榷。一位博主的解释:掘金

t1.join();

等价于

synchronized (t1) {
// 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
            while (t1.isAlive()) {
                t1.wait(0);
            }
        }

举例

//  在主线程调用t1的join方法,等价于把主线程放入t1的waitSet进行等待

@Slf4j
public class test {

    static int r1 = 0;
    static int r2 = 0;
    public static void main(String[] args) throws InterruptedException {
        test2();
    }
    private static void test2() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r1 = 10;
        });
        Thread t2 = new Thread(() -> {
            try {
                sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r2 = 20;
        });
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();    //在主线程调用t1的join方法,等价于把主线程放入t1的waitSet进行等待
        t2.join();
        long end = System.currentTimeMillis();
        log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
    }


}

Guess you like

Origin blog.csdn.net/Mrrr_Li/article/details/121469365