多线程如何进行线程通信

线程通信

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

相关推荐
qq_4419960518 分钟前
Mybatis官方生成器使用示例
java·mybatis
巨大八爪鱼25 分钟前
XP系统下用mod_jk 1.2.40整合apache2.2.16和tomcat 6.0.29,让apache可以同时访问php和jsp页面
java·tomcat·apache·mod_jk
码上一元2 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田2 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
魔道不误砍柴功4 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
枫叶_v4 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
wclass-zhengge4 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
路在脚下@4 小时前
Springboot 的Servlet Web 应用、响应式 Web 应用(Reactive)以及非 Web 应用(None)的特点和适用场景
java·spring boot·servlet
黑马师兄4 小时前
SpringBoot
java·spring