Java 锁机制详解(一)synchronized

2020-04-22  本文已影响0人  Parallel_Lines

本系列将注重对 synchronized、volatile、Lock 和其它线程关键字进行解析。

一、 概念

学习 synchronized 锁之前,先明确一些概念。

1. 锁池和等待池

线程在进入 synchronized 代码块前必须先获取对象的锁的拥有权,如果此时锁被其它线程持有,线程拿不到锁,即进入该对象的锁池中。

锁池中的线程有竞争锁的权利,即有可能在 cpu 下次调度时执行获得 synchronized 代码块的执行权。

线程在 synchronized 中执行了 wait 方法,线程在释放了该对象的锁后,进入该对象的等待池中。

等待池中的线程没有竞争锁的权利,如果没有被唤醒,线程则会一直等待,同时释放 cpu 资源。

总结:
进入 synchronized 代码块前如果拿不到锁,则进入锁池等待下次竞争;
进入 synchronized 代码块后如果调用对象的 wait,则线程释放锁,并进入等待池。直到 notify 唤醒,从等待池进入锁池,重新获得竞争锁的权利。

2. notify 和 notifyAll

不论是 notify 还是 notifyAll,仅仅是将线程从等待池移入锁池,使线程重新获得竞争锁的权利。

仅仅是有权利竞争,并不代表下次一定由 notify 的线程执行。
锁池中的线程仍需等待 notify 所在 synchronized 代码块执行完才能竞争锁。

notify 后只有随机一个线程会由等待池进入锁池,而 notifyAll 会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。

综上,notify 可能会导致死锁,而 notifyAll 则不会。

二、 代码

1. 最基础 wait notify

一个线程 wait,另一个线程 notify

private final Object lock = new Object();

private Thread thread1 = new Thread() {
    @Override
    public void run() {
        super.run();
        msg.in("thread1 start"); //不会阻塞
        synchronized (lock) {
            msg.in("thread1 sync start");
            try {
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            msg.in("thread1 sync end");
        }
        msg.in("thread1 end");
    }
};

private Thread thread2 = new Thread() {
    @Override
    public void run() {
        super.run();
        msg.in("thread2 start");//不会阻塞
        synchronized (lock) {
            msg.in("thread2 sync start");
            lock.notify();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            msg.in("thread2 sync end"); //notify后,直到锁内代码执行完,唤醒的线程都无法执行
        }
        msg.in("thread2 end");
    }
};

2. 俩个线程交替执行

无法指定先后顺序。

private class InTurnThread extends Thread {
    private String name;

    public InTurnThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        synchronized (lock) {
            while (!isStop) {
                msg.in(name + " sync start");
                lock.notifyAll();
                try {
                    Thread.sleep(1000);
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                msg.in(name + "sync end");
            }
            lock.notifyAll();
        }
    }
}

3. 多个线程顺序交替执行

如线程 A、B、C 的执行顺序为 ABCABCABC...

private class OrderInTurnThread extends Thread {

    private int order;

    public OrderInTurnThread(int order) {
        this.order = order;
    }

    @Override
    public void run() {
        super.run();
        synchronized (lock) {
            while (!isStop) {
                // 符合条件 执行后 唤醒其它所有等待线程
                if (flag % THREAD_COUNT == order) {
                    msg.in(order + "");
                    flag++;
                    lock.notifyAll();
                }
                // 不符合条件 或 符合条件执行完毕 进入等待 交给下个线程执行
                try {
                    Thread.sleep(500);
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            lock.notifyAll();
        }
        msg.in(order + " end");
    }
}

下接 Java 锁机制详解(二)volatile

[TOC]

上一篇下一篇

猜你喜欢

热点阅读