【Java 并发编程】一文了解线程间有哪些通信方式?

一文了解线程间有哪些通信方式?

  • 1. synchronized 内置锁
  • 2. volatile 关键字
  • 3. 等待/通知机制
    • 3.1 等待
      • wait()
      • wait(long)
      • wait(long, int)
      • 等待方需遵循如下原则
    • 3.2 通知
      • notify()
      • notifyAll()
      • 通知方需遵循如下原则
      • notify() 和 notifyAll() 应该用谁?
  • 4. 管道输入/输出流
  • 5. Thread.join()
    • 面试题
  • 6. ThreadLocal

【Java 并发编程】一文了解线程间有哪些通信方式?_第1张图片

1. synchronized 内置锁

关键字 synchronized 可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

2. volatile 关键字

关键字 volatile 可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

3. 等待/通知机制

可以通过 Java 内置的等待/通知机制 - wait()、notify/notifyAll() 实现一个线程修改一个对象的值,而另一个线程感知到了变化,然后进行相应的操作。

3.1 等待

wait()

调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回。

需要注意:调用 wait() 方法后,会释放对象的锁。

wait(long)

超时等待一段时间,这里的参数时间是毫秒,也就是等待长达 n 毫秒,如果没有通知就超时返回。

wait(long, int)

对于超时时间更细粒度的控制,可以达到纳秒。

等待方需遵循如下原则

  1. 获取对象的锁;

  2. 如果条件不满足,那么调用对象的 wait() 方法,被通知后仍要检查条件;

  3. 条件满足执行业务逻辑。

synchronized (对象) {
    while (条件不满足) {
        对象.wait();
    }
    do something;
}

3.2 通知

notify()

通知一个在对象上等待的线程,使其从 wait() 方法返回,而返回的前提是该线程获取到了对象的锁,没有获得锁的线程重新进入 WAITING 状态。

notifyAll()

通知所有等待在该对象上的线程

通知方需遵循如下原则

  1. 获取对象的锁;

  2. 改变条件;

  3. 通知所有等待在对象的线程。

synchronized (对象) {
    改变条件;
    对象.notifyAll();
}

notify() 和 notifyAll() 应该用谁?

尽可能用 notifyAll(),谨慎使用 notify()。因为 notify() 只会唤醒一个线程,我们无法确保被唤醒的这个线程一定就是我们需要唤醒的线程

4. 管道输入/输出流

管道输入/输出流和普通的文件输入/输出流或者网络输入/输出流不同之处在于,它主要用于线程之间的数据传输,而传输的媒介为内存。

管道输入/输出流主要包括了如下4种具体实现:PipedOutputStream、PipedInputStream、PipedReader 和 PipedWriter,前两种面向字节,而后两种面向字符。

5. Thread.join()

如果一个线程A执行了 Thread.join() 语句,其含义是:当前线程A等待 Thread 线程终止之后才从 Thread.join() 返回。线程 Thread 除了提供 join() 方法之外,还提供了join(long millis) 和 join(long millis,int nanos) 两个具备超时特性的方法。

面试题

现在有 T1、T2、T3 三个线程,怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执行?

用 Thread.join() 方法即可,在 T3 中调用 T2.join(),在 T2 中调用 T1.join()。

6. ThreadLocal

ThreadLocal,即线程变量,是一个以 ThreadLocal 对象为键、任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据一个 ThreadLocal 对象查询到绑定在这个线程上的一个值。

可以通过 set(T) 方法来设置一个值,在当前线程下再通过 get() 方法获取到原先设置的值。

你可能感兴趣的:(Java,java,jvm,开发语言)