27.Java 线程间通信(synchronized 实现线程间通信、Lock 实现线程间通信)

一、线程间通信

1、概述
  • 线程间通信的模型有两种:共享内存和消息传递
2、多线程编程步骤(中)
  1. 创建资源类,在资源类中创建属性和操作方法

  2. 在资源类操作方法进行判断、操作、通知

  3. 创建多个线程,调用资源类中的操作方法


二、synchronized 实现线程间通信

1、需求
  • 通过使用两个线程对值(0)进行操作,一个线程加 1,一个线程减 1,交替实现多次
2、具体实现
(1)资源类
  • Share 类
java 复制代码
package com.my.communicate;

public class Share {

    // 初始值
    private int number;

    // 加 1 的方法
    public synchronized void increase() throws InterruptedException {

        // number 为 0 则等待
        if (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "  " + number);

        // 通知其他线程
        this.notifyAll();
    }

    // 减 1 的方法
    public synchronized void decrease() throws InterruptedException {

        // number 为 0 则等待
        if (number != 1) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "  " + number);

        // 通知其他线程
        this.notifyAll();
    }
}
(2)多线程测试
  • ShareTest 类
java 复制代码
package com.my.communicate;

public class ShareTest {
    public static void main(String[] args) {
        Share share = new Share();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.increase();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB");

        thread1.start();
        thread2.start();
    }
}
3、虚假唤醒
  • 在当前 synchronized 实现线程间通信案例中再增加两个线程,执行结果会不符合预期,根本原因是虚假唤醒问题

  • 如果一个线程执行完毕后,通知其他线程,该线程又进入等待睡眠,被唤醒后,if 语句不会进行判断

  • 需要将 if 语句换成 while 语句,因为在哪里等待睡眠就会在哪里被唤醒,需要使用 while 语句再次进行判断

4、改进
(1)资源类
  • ShareImprove 类
java 复制代码
package com.my.communicate;

public class ShareImprove {

    // 初始值
    private int number;

    // 加 1 的方法
    public synchronized void increase() throws InterruptedException {

        // number 为 0 则等待
        while (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "  " + number);

        // 通知其他线程
        this.notifyAll();
    }

    // 减 1 的方法
    public synchronized void decrease() throws InterruptedException {

        // number 为 0 则等待
        while (number != 1) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "  " + number);

        // 通知其他线程
        this.notifyAll();
    }
}
(2)多线程测试
  • ShareTestImprove 类
java 复制代码
package com.my.communicate;

public class ShareTestImprove {
    public static void main(String[] args) {
        Share share = new Share();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.increase();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB");
        Thread thread3 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.increase();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "CC");
        Thread thread4 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "DD");

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

三、Lock 实现线程间通信

1、需求
  • 通过使用两个线程对值(0)进行操作,一个线程加 1,一个线程减 1,交替实现多次
2、具体实现
  • LShare 类
(1)资源类
java 复制代码
package com.my.communicate;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LShare {

    // 初始值
    private int number;

    // 创建可重入锁
    private Lock lock;

    // 创建 Condition 对象
    private Condition condition;

    public LShare() {
        number = 0;
        lock = new ReentrantLock();
        condition = lock.newCondition();
    }

    // 加 1 的方法
    public void increase() {
        lock.lock();
        try {
            while (number != 0) {

                // 等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "  " + number);

            // 通知其他线程
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    // 减 1 的方法
    public void decrease() {
        lock.lock();
        try {
            while (number != 1) {

                // 等待
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "  " + number);

            // 通知其他线程
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
(2)多线程测试
  • LShareTest 类
java 复制代码
package com.my.communicate;

public class LShareTest {
    public static void main(String[] args) {
        LShare lShare = new LShare();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                lShare.increase();
            }
        }, "AA");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                lShare.decrease();
            }
        }, "BB");
        Thread thread3 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                lShare.increase();
            }
        }, "CC");
        Thread thread4 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                lShare.decrease();
            }
        }, "DD");

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}
相关推荐
whatever who cares5 分钟前
android/java中gson的用法
android·java·开发语言
gongzemin6 分钟前
使用阿里云ECS部署前端应用
前端·vue.js·后端
摇滚侠8 分钟前
Spring Boot3零基础教程,为什么有Reactive-Stream 规范,响应式编程,笔记101
java·spring boot·笔记
用户83562907805110 分钟前
使用Python合并Word文档:实现高效自动化办公
后端·python
周杰伦fans18 分钟前
C# 中 Entity Framework (EF) 和 EF Core 里的 `AsNoTracking` 方法
开发语言·c#
小灰灰搞电子21 分钟前
Rust Slint实现控件尺寸的扩展与收缩源码分享
开发语言·后端·rust
☆cwlulu23 分钟前
git分支管理详解
开发语言·git·青少年编程
天天摸鱼的java工程师23 分钟前
八年 Java 开发手敲:SpringBoot+SpringSecurity+JWT 实战,前后分离权限注解落地就能跑
java·后端
冰淇淋@25 分钟前
idea启动项目报错java: OutOfMemoryError: insufficient memory
java·ide·intellij-idea
techzhi27 分钟前
this view is read-only (IntelliJ IDEA)
java·ide·intellij-idea