刘俊凯 发表于 2023-11-23 22:04:59

线程间通信

线程间通信

多线程编程步骤(中)

第一,创建资源类,创建属性和操作方法;第二,在资源操作方法,1)判断 2)工作 3)通知;第三,创建多线程调用资源类的方法。
案例

要求,有两个线程,实现对一个初始值为0的变量,一个线程对值+1,一个线程对值-1。
代码实现

/**
* @author 长名06
* @version 1.0
* 线程通信案例 两个线程对一个值进行 decr incr
* 用synchronized关键字实现
*/

class Share {

    private int number;

    public synchronized void incr() throws InterruptedException {
      /**
         * 这样写,会出现虚假唤醒问题,因为如果当前线程被等待,然后被唤醒时,if语句,就不会再次进行判断
         * 有可能出现,此时的number != 0 当时依旧进行了 +1操作 减方法类似
         * wait()方法再api文档中,就提醒,在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用:
         * 线程在哪里被阻塞就会在哪里,被唤醒,也就是说线程被阻塞时,是满足number!= 0,所以阻塞,但是因为一个线程执行完后,释                  
         * 放锁,然后唤醒等待的线程,是随机唤醒的,有可能当前+1的条件依旧不满足,但是系统却唤醒了该线程,因为是if语句,在                       
         * this.wait()处被唤醒,程序继续执行,导致其实条件不满足,却执行了+1操作,所以使用while()循环进行判断,只能当条件满                  
         * 足且线程被唤醒才执行incr方法
         * if (number != 0){//条件
         *    this.wait();
         * }
         */
      while (number != 0) {
            this.wait();
      }
      //加1
      number++;
      System.out.println(Thread.currentThread().getName() + "\t" + number);
      //通知其他线程
      this.notifyAll();
    }

    public synchronized void decr() throws InterruptedException {
      while (number != 1) {
            this.wait();
      }
      //减1
      number--;
      System.out.println(Thread.currentThread().getName() + "\t" + number);
      //通知其他线程
      this.notifyAll();
    }
}

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

      new Thread(() -> {
            for (int i = 0; i < 25; i++) {
                try {
                  share.incr();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      }, "aa").start();

      new Thread(() -> {
            for (int i = 0; i < 25; i++) {
                try {
                  share.decr();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      }, "bb").start();
    }
}多线程编程步骤(下)

第一,创建资源类,创建属性和操作方法;第二,在资源操作方法,1) 判断 2)工作 3)通知;第三,创建多线程调用资源类的方法;第四,防止虚假唤醒问题。
Lock实现上述案例

代码

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

/**
* @author 长名06
* @version 1.0
*/
//第一步创建资源类,属性和操作方法
class ShareByLock {
    private int number;

    //获得锁
    private final ReentrantLock lock = new ReentrantLock();

    //为当前锁,创建一个新的condition,并绑定到该锁上
    private Condition condition = lock.newCondition();

    public void incr() throws InterruptedException {
      //上锁
      lock.lock();
      //第二步 进行
      // 1.判断(线程切换的条件)
      // 2.执行(线程执行的具体操作)
      // 3.通知(唤醒等待的其他线程)
      try {
            //判断
            //第四步 防止虚假唤醒现象
            while (number != 0) {
                condition.await();
            }
            //执行
            number++;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //通知
            condition.signalAll();
      } finally {
            //解锁
            lock.unlock();
      }
    }

    public void decr() throws InterruptedException {
      //上锁
      lock.lock();
      try {
            //判断
            while (number != 1) {
                condition.await();
            }
            //执行
            number--;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //通知
            condition.signalAll();
      } finally {
            //解锁
            lock.unlock();
      }
    }
}

public class ThreadDemoByLock {
    public static void main(String[] args) {

      ShareByLock shareByLock = new ShareByLock();
      //第三步 创建多个线程调用资源类的方法
      new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                  shareByLock.incr();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      }, "aa").start();

      new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                  shareByLock.decr();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      }, "bb").start();

      new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                  shareByLock.incr();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      }, "cc").start();

      new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                  shareByLock.decr();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      }, "dd").start();

    }
}只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 线程间通信