多线程如何进行线程通信

线程通信

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

相关推荐
码出财富2 小时前
SpringBoot 内置的 20 个高效工具类
java·spring boot·spring cloud·java-ee
我是小疯子663 小时前
Python变量赋值陷阱:浅拷贝VS深拷贝
java·服务器·数据库
森叶3 小时前
Java 比 Python 高性能的原因:重点在高并发方面
java·开发语言·python
二哈喇子!3 小时前
Eclipse中导入外部jar包
java·eclipse·jar
微露清风3 小时前
系统性学习C++-第二十二讲-C++11
java·c++·学习
进阶小白猿4 小时前
Java技术八股学习Day20
java·开发语言·学习
gis开发4 小时前
【无标题】
java·前端·javascript
Wpa.wk4 小时前
性能测试 - 搭建线上的性能测试环境参考逻辑图
java·经验分享·测试工具·jmeter·性能测试
代码村新手4 小时前
C++-类和对象(中)
java·开发语言·c++
葵花楹4 小时前
【JAVA课设】【游戏社交系统】
java·开发语言·游戏