多线程如何进行线程通信

线程通信

除了使用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多平台发布

相关推荐
小七在进步8 分钟前
C++入门(2)
java·jvm·c++
To0R13 分钟前
Agent 上线前必须过的五道门(附 Spring Boot 实现)
java
vipxieliang21 分钟前
固定电话验证详解:区号、号码、分机号的完整验证
java·spring boot
步行cgn28 分钟前
Spring Boot 主入口类上的 @Enable 和 @Scan 注解详解
java·spring boot·后端
lhldsg29 分钟前
全民健身解决方案软件开发实战:从架构设计到部署指南
java·前端·数据库·小程序
两点王爷31 分钟前
Java 与前端加载 MVT 数据:从服务端切片到浏览器渲染
java·前端·状态模式
TinyMemory1 小时前
Java 面向对象核心入门(九):方法重写 Override|彻底分清重载与重写
java·面向对象·override·方法重写·重载与重写
LaughingZhu1 小时前
Product Hunt 每日热榜 | 2026-09-08
java·ide·深度学习·百度·intellij-idea
IT枫斗者枫哥1 小时前
Java 文件导出:写完了,为什么还不能标记成功?
java
陈皮波比茶1 小时前
java笔记-typora快捷键
java