Java并发编程——线程间通信

一、volatile 关键字

为什么volatile关键字可以?因为之前说过了,此关键字能保证变量的可见性,也就是说变量一旦被修改,立马能被其他线程所感知

例子如下:

private static volatile boolean flag=true;

private static void setFlag(){
    flag=false;
}
public static void main(String[] args) {
    new Thread(()->{
        System.out.println("还没变");
        while (flag){
            // flag不改变 就一直死循环直至发现值改变
        }
        System.out.println("我感知到变化了");
    }).start();
    try {
        //等待1s才执行下一个线程
        Thread.sleep(1000); 
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    new Thread(()->{
        setFlag();
        System.out.println("我修改了");
    }).start();
}

二、等待/通知机制

相关方法为:

  • notify():通知一个在对象上等待的线程,使其从wait()方法返回,返回的前提是该线程获得了锁
  • notifyAll():通知所有在该对象上等待的线程
  • wait():调用该方法进入waiting状态并会释放锁,只有被其他线程通知或者中断才返回
  • wait(long):超时等待一段时间,到时间了还没通知就返回
  • wait(long,int):增加了超时时间单位的控制

例子如下:

public static Object flag=true;

public static void main(String[] args) throws InterruptedException {
    new Thread(()->{
        synchronized (flag){
            System.out.println("线程1:进入等待");
            try {
                flag.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程1:从等待中归来");
        }
    }).start();
   Thread.sleep(1000);
   new Thread(()->{
       synchronized (flag){
           System.out.println("线程2:上面那个线程调用wait后会释放锁,所以到我啦");
           flag.notify();
           System.out.println("线程2:我把它唤醒了,但是它需要等我执行完释放掉锁才会返回");
       }
   }).start();
}

结果:

在这里插入图片描述

注意:这个使用需要配合synchronized 使用

三、管道通信

管道输入流/输出流主要包括如下4个具体实现:

  • PipedInputStream
  • PipedOutputStream
  • PipedReader
  • PipedWriter

前两种面向字节,后两种面向字符

例子如下:

public static void main(String[] args) throws InterruptedException, IOException {
        // 读为接收
        PipedReader in = new PipedReader();
        // 写为输出
        PipedWriter out = new PipedWriter();
        // 将管道输入和输出连接起来
        out.connect(in);
        new Thread(() -> {
            int receive = 0;
            while (true) {
                try {
                    if (((receive = in.read()) != -1)) {
                        System.out.println("接收到了:"+receive);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()->{
            try {
                // 这里输入,给那边接收
                out.write(11111);
                // 死循环防止输入端结束 管道断裂
                while (true){}
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

    }

结果:

在这里插入图片描述

四、Thread.join

这个是干嘛呢?就是等待线程结束

假设线程A执行了threadB.join()语句,其含义是:当前线程A等待线程B执行结束后才返回。说白了就是等待其他线程执行后才执行

例子如下:

public static void main(String[] args) throws InterruptedException, IOException {
      System.out.println("主线程:我开始执行啦");
      Thread threadB = new Thread(() -> {
          System.out.println("线程B:我开始执行啦");
          System.out.println("线程B:我要睡会儿");
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println("线程B:我睡醒执行完了");
      });
      threadB.start();
      System.out.println("主线程:我等待线程B执行完我再执行");
      threadB.join();
      System.out.println("主线程:线程B执行完了,到我执行了");
  }

结果:主线程一定是最后才执行完的

在这里插入图片描述

但是如果把join注释掉,那么线程B一定是最后执行完的:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值