Java 线程间通信

作者: Tinyspot | 来源:发表于2022-09-07 22:18 被阅读0次

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...

相关文章

  • 线程间通信剖析——Java进阶

    Java线程间通信剖析 本文将介绍常用的线程间通信工具CountDownLatch、CyclicBarrier和P...

  • 2.Java内存模型

    1.java并发编程的线程间通信及线程间如何同步线程间通信分为:共享内存,消息传递。线程间同步:共享内存是代码指定...

  • Java多线程(2)

    Java多线程(2) 线程间的通信 线程间的通信又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等...

  • Java - 线程间通信

    涉及到的知识点:thread.join(), object.wait(), object.notify(), Co...

  • Java线程间通信

    涉及到多个线程协同完成某个任务的时候,就用到了线程间通信的相关知识点。这其中涉及到的知识点有:(1)thread....

  • Java 线程间通信

    线程间的交互和通信 一个线程启动另一个线程public static void main(String[] arg...

  • Java 线程间通信

    1. 线程之间如何通信 共享内存(隐式通信) 消息传递(显式通信 wait / notify synchroniz...

  • Java线程<第四篇>:线程间通信

    线程间通信是Java线程必须掌握的课程之一。线程间的通信的前提是,必须要保证线程还活着,可以使用阻塞方法,将线程暂...

  • Java多线程:线程间通信之volatile与sychroniz

    由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信。 ...

  • Java线程简介

    本文将介绍Java线程的状态、线程的中断、线程间通信和线程的实现。 线程的状态 Java语言定义了6种不同的线程状...

网友评论

    本文标题:Java 线程间通信

    本文链接:https://www.haomeiwen.com/subject/lkkjnrtx.html