行业资讯 2025年08月6日
0 收藏 0 点赞 425 浏览 3186 个字
摘要 :

文章目录  多线程通信概述和案例 虚假唤醒问题 解决办法: Lock实现线程间通信 本文主要讲解Java并发编程:线程间通信问题,我们来一起学习下如何实现Java并发编程的……




  •  多线程通信概述和案例
  • 虚假唤醒问题
    • 解决办法:
  • Lock实现线程间通信

本文主要讲解Java并发编程:线程间通信问题,我们来一起学习下如何实现Java并发编程的线程间通信。

 多线程通信概述和案例

多线程编程步骤:

  • 1、 创建资源类,在资源类创建属性和操作方法;
  • 2、 在资源类操作方法:判断、干活、通知;
  • 3、 创建多个线程,调用资源类的操作方法;

例子:

有两个线程,对一个初始化为0的变量,一个对其进行加1操作(在值为0的情况下),一个对其进行减1操作(在值为1的情况下)

代码案例:

//第一步 创建资源类,定义属性和操作方法
class Share {
    //初始值
    private int number = 0;

    //+1的方法
    public synchronized void incr() throws InterruptedException {
        //第二步 判断 干活 通知
        if(number == 1) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + \":\" + number);
        this.notifyAll();
    }
    //-1的方法
    public synchronized void decr() throws InterruptedException {
        if(number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + \":\" + number);
        this.notifyAll();
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {

        Share share = new Share();

        new Thread(()->{
            for(int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, \"增大线程\").start();

        new Thread(()->{
            for(int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, \"减小线程\").start();
    }
}

虚假唤醒问题

假设我们再增加一个增大线程减小线程,也就是说有两个增大线程和两个减小程,现在就可能会出现虚假唤醒的问题:

首先有两个前提:

  • 1、wait()后,进程会释放锁
  • 2、在哪里睡,就在哪里醒
  • 3、被notifyAll()唤醒后,处于wait()状态的线程需要先竞争锁才能继续执行wait()后面的操作。

步骤:

  • 1、假设有A、B、C、D四个线程,A和C是增加线程,B和D是减小线程。
  • 2、假设A和C均处于wait()状态,B调用notifyAll()后,C竞争到锁被唤醒,进行了+1操作。
  • 3、C调用notifyAll(),将A唤醒,此时会将number值加到2。那3(即那些大于2的值)是怎么来的?

在上面的第三步中,C调用notifyAll()后,A获得锁之前,C又拿到了锁并调用wait()阻塞了,此时A被唤醒,它的notifyAll()又能将C唤醒,所以会出现3。

解决办法:

将if改成while:

//第一步 创建资源类,定义属性和操作方法
class Share {
    //初始值
    private int number = 0;

    //+1的方法
    public synchronized void incr() throws InterruptedException {
        //第二步 判断 干活 通知
        while(number == 1) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + \":\" + number);
        this.notifyAll();
    }
    //-1的方法
    public synchronized void decr() throws InterruptedException {
        while(number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + \":\" + number);
        this.notifyAll();
    }
}

Lock实现线程间通信

1)lock.lock()lock.unlock()可以实现synchronized的效果。

2)condition.await()condition.singalAll()可以实现wait()notifyAll()的效果。

代码案例:

public class ThreadDemo2 {
    public static void main(String[] args) {
        AnotherShare share = new AnotherShare();
         new Thread(()->{
             for(int i = 0; i < 10; i++) {
     
                 try {
                     share.incr();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, \"A\").start();
         new Thread(()->{
             for(int i = 0; i < 10; i++) {
                 try {
                     share.decr();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, \"B\").start();
        new Thread(()->{
            for(int i = 0; i < 10; i++) {
     
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, \"C\").start();
        new Thread(()->{
            for(int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
            }
        }, \"D\").start();
    }

}

//第一步,创建资源类,定义属性和方法
class AnotherShare {
    private int number = 0;

    //创建Lock
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    //+1操作
    public void incr() throws InterruptedException {
   
        //上锁
        lock.lock();
        try {
            while(number != 0) {
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + \":\" + number);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
    //-1操作
    public void decr() throws InterruptedException {
        //上锁
        lock.lock();
        try {
            while(number != 1) {
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + \":\" + number);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

以上就是Java并发编程:线程间通信的全部内容,希望对你有帮助,学习愉快哦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/9819.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号