当前位置:
首页
文章
移动端
详情

Java 线程间通信

1. 线程之间如何通信

  • 共享内存(隐式通信)
  • 消息传递(显式通信 wait / notify synchronized)

1.2 阻塞

  • BLOCKED 和 WAITING 的线程都处于阻塞状态,不占用 CPU 时间片
  • BLOCKED 线程会在 Owner 线程释放锁时唤醒
  • WAITING 线程会在 Owner 线程调用 notify 或 notifyAll 时唤醒,但唤醒后并不意味着立刻获得锁,仍需进入 EntryList 重新竞争

2. wait() / notify() / notifyAll()

  • 都是 Object 对象的方法,必须获得此对象的锁,才能调用这些方法
  • obj.wait()
  • obj.notify() 唤醒 obj 上任意一个线程
  • obj.notifyAll() 唤醒 obj 上所有正在 WaitSet 等待的线程

2.1 wait()

public class Demo {
    // 声明为 final, 表示引用不可变,若引用变了,synchronized 锁的就是不同对象
    static final Object obj = new Object();
    public static void main(String[] args) throws InterruptedException {
        obj.wait();
    }
}

运行会抛异常 Exception in thread "main" java.lang.IllegalMonitorStateException,因为此时并未获得锁

public class Demo {
    static final Object obj = new Object();
    public static void main(String[] args) throws InterruptedException {
        synchronized (obj) {
            obj.wait();
        }
    }
}

使用 synchronized 先获得锁,成为该锁的 owner, 然后再调用 wait()

2.2 wait(long n)

有时限的等待,到 n 毫秒后结束等待,或被 notify()

    public final void wait() throws InterruptedException {
        wait(0);
    }

    public final native void wait(long timeout) throws InterruptedException;
    public final void wait(long timeout, int nanos) throws InterruptedException {}

示例

static final Object obj = new Object();
public static void main(String[] args) {
    new Thread(() -> {
        synchronized (obj) {
            log.debug("start...");
            try {
                obj.wait(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("do something...");
        }
    }).start();
}

2.3 notify() / notifyAll()

@Slf4j
public class Demo {

    static final Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            synchronized (obj) {
                log.debug("run...");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("do something...");
            }
        }).start();

        new Thread(() -> {
            synchronized (obj) {
                log.debug("run...");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("do something...");
            }
        }).start();

        TimeUnit.SECONDS.sleep(1);
        synchronized (obj) {
            // obj.notify();
            obj.notifyAll();
        }
    }
}

3. wait() vs sleep()

  • wait(), notify() 和 notifyAll() 被定义在 Object 类,而 sleep() 定义在 Thread 类
  • wait() 要在同步代码块内使用(要先获取对象锁,和 synchronized 一起用),而 sleep() 不需要
  • wait() 在等待的时候会释放对象锁,而 sleep() 在睡眠的同时,不会释放对象锁
public class Thread implements Runnable {
    public static native void sleep(long millis) throws InterruptedException;
}

public class Object {
    public final native void wait(long timeout) throws InterruptedException;
}

3.1 验证 sleep() 不释放锁

@Slf4j
public class Demo {
    static final Object obj = new Object();
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            synchronized (obj) {
                log.debug("start...");
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("do something...");
            }
        }).start();

        TimeUnit.SECONDS.sleep(1);

        // main 线程想获取锁,并执行逻辑
        synchronized (obj) {
            log.debug("run...");
        }
    }
}

执行结果

22:16:16.687 [Thread-0] DEBUG com.example.concrete.Demo - start...
22:16:19.691 [Thread-0] DEBUG com.example.concrete.Demo - do something...
22:16:19.691 [main] DEBUG com.example.concrete.Demo - run...

免责申明:本站发布的内容(图片、视频和文字)以转载和分享为主,文章观点不代表本站立场,如涉及侵权请联系站长邮箱:xbc-online@qq.com进行反馈,一经查实,将立刻删除涉嫌侵权内容。