多线程如何进行线程通信

线程通信

除了使用synchronized来对代码块和方法进行同步外,jdk1.5之后还有一种Lock同步锁的方式进行同步 使用lock.lock()来进行加锁,使用lock.unlock()方法来释放锁 既然可以使用lock来代替synchronized,那么如何进行处理synchronized与wait()、notify()、notifyAll()的线程通信机制呢 在使用lock时使用Condition来进行线程通信

下面来使用两种方式来分别展示一下线程间通信

使用Object的wait()、notify进行线程通信

阻塞

调用wait()方法 ,将阻塞挂起等待其他线程的通知,进入该对象的线程等待池中,调用wait()方法之前,线程必须要获得该对象的对象级别锁,即只能在同步块或者同步方法中使用,否则会报IllegalMonitorStateException异常

唤醒

调用notify()方法和notifyAll()方法来通知那些等待该对象锁的其他线程,(如果有多个线程等待,notify会任意挑选一个线程来进行通知,notifyAll会对所有该对象上由于调用wait方法而被挂起的线程进行通知,),唤醒之后的线程会进入该对象的锁池中,需要竞争到对象的监视器锁才可以继续执行,调用notify()方法和notifyAll()方法之前,线程必须要获得该对象的对象级别锁,即只能在同步块或者同步方法中使用

除了调用notify()方法和notifyAll()方法来唤醒线程之外,还可以使用中断的方式来使得线程在wait()处抛出InterruptedException异常而返回并终止

如果使用的是wait(timeout)方法进行阻塞的,那么也会由于在指定时间内没有被唤醒而因为超时返回

java 复制代码
/**
 * wait()/notify()/notifyAll()是Object的方法
 * 只能在synchronized方法或者代码块中使用,否则会报IllegalMonitorStateException异常
 * 交替打印1-100
 */
public class TestThreadSignal {
    public static void main(String[] args) {
        PrintRunnable runnable = new PrintRunnable();
        new Thread(runnable,"线程一").start();
        new Thread(runnable,"线程二").start();
    }
}

class PrintRunnable implements Runnable{
    int num = 1;
    @Override
    public void run() {
      
        while (true){
            synchronized (this){
                notify();// 唤醒wait的线程
                if(num <= 100){
                    System.out.println(Thread.currentThread().getName() + "打印" + num++);
                } else {
                    break;
                }
                try {
                    wait(); // 释放当前的锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
虚假唤醒现象

有时在没有被其他线程调用notify/notifyAll,或者没有被中断,或者没有等待超时,也有可能会从挂起状态变为运行状态(虚假唤醒),虽然概率很低,但是最好还是使用while(条件)来一直查看条件是否满足

java 复制代码
synchronized(obj){
  while(条件){
    obj.wait();
  }
}

使用condition的await()、signal()进行线程通信

java 复制代码
/**
 * 使用lock和condition来进行线程通信
 * condition中的await()、signal()、signalAll()方法分别对应于Object中的wait()、notify()、notifyAll()方法
 * 两个线程交替打印1-100
 */
public class TestThreadSignalForLock {
    public static void main(String[] args) {
        PrintRunnableForLock runnable = new PrintRunnableForLock();
        new Thread(runnable,"线程一").start();
        new Thread(runnable,"线程二").start();
    }
}

class PrintRunnableForLock implements Runnable{
    int num = 1;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    @Override
    public void run() {
        while (true){
           try{
               lock.lock();
               condition.signal();// 唤醒线程
               if(num <= 100){
                   System.out.println(Thread.currentThread().getName() + "打印" + num++);
               } else {
                   break;
               }
               try {
                   condition.await(); // 释放当前的锁
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           } finally {
               lock.unlock();
           }

        }
    }
}

zhhll.icu/2020/多线程/基础...

本文由mdnice多平台发布

相关推荐
JAVA面经实录91715 分钟前
Java多线程并发高频面试100题(完整版·含答案·背诵版)
java·开发语言·面试
XiYang-DING19 分钟前
【Java EE】TCP—流量控制和拥塞控制
java·tcp/ip·java-ee
BIG_PEI38 分钟前
检查并安装Redis
java
大貔貅喝啤酒40 分钟前
基于Windows下载安装Android Studio 3.3.2版本教程(2026详细图文版)
android·java·windows·android studio
奋斗的小方42 分钟前
Java基础篇09:项目实战
java·开发语言
海兰43 分钟前
【第21篇-续】graph-Stream-Node改造为适配openAI模型示例
java·人工智能·spring boot·spring·spring ai
vKd0Ff21L1 小时前
如何在Dev-C++中设置TDM-GCC为默认编译器第九十一篇
java·jvm·c++
武子康1 小时前
Java-221 RocketMQ 消息存储核心原理:CommitLog、ConsumerQueue、IndexFile 与消息过滤机制
java·大数据·分布式·消息队列·rabbitmq·rocketmq·java-rocketmq
北风toto1 小时前
为什么 IntelliJ IDEA Community 无法开发 Vue?——附解决方案
java·vue.js·intellij-idea
programhelp_1 小时前
Google 2026 New Grad SDE VO 三轮面试详解 | 含Behavioral、Coding、Design
java·服务器·数据库