线程通信的四种方式

线程通信的四种方式线程之间为什么要通信?通信的目的是为了更好的协作,线程无论是交替式执行,还是接力式执行,都需要进行通信告知。那么java线程是如何通信的呢,大致有以下四种方式。Java线程的通信方式volatile等待/通知机制join方式threadLocalvolatile关键字方式volatile有两大特性,一是可见性,二是有序性,禁止指令重排序,其中可见性就是可以让线程之间进行通信。…

线程之间为什么要通信?

通信的目的是为了更好的协作,线程无论是交替式执行,还是接力式执行,都需要进行通信告知。那么java线程是如何通信的呢,大致有以下四种方式。

Java线程的通信方式
  1. volatile
  2. 等待/通知机制
  3. join方式
  4. threadLocal

volatile关键字方式

volatile有两大特性,一是可见性,二是有序性,禁止指令重排序,其中可见性就是可以让线程之间进行通信。

volatile语义保证线程可见性有两个原则保证

  • 所有volatile修饰的变量一旦被某个线程更改,必须立即刷新到主内存
  • 所有volatile修饰的变量在使用之前必须重新读取主内存的值

volatile保证可见性原理图
在这里插入图片描述
工作内存2能够感知到工作内存1更新a值是靠的总线,工作内存1在将值刷新的主内存时必须经过总线,总线就能告知其他线程有值被改变,那么其他线程就会主动读取主内存的值来更新。

示例

/** * * @author wengyz * @version VolatileDemo.java, v 0.1 2020-04-12 22:09 */
public class VolatileDemo { 
   

    private static volatile boolean flag = true;

    public static void main(String[] args) { 
   

        new Thread(new Runnable() { 
   
            @Override
            public void run() { 
   
                while (true){ 
   
                    if (flag){ 
   
                        System.out.println("trun on");
                        flag = false;
                    }
                }
            }
        }).start();

        new Thread(new Runnable() { 
   
            @Override
            public void run() { 
   
                while (true){ 
   
                    if (!flag){ 
   
                        System.out.println("trun off");
                        flag = true;
                    }
                }
            }
        }).start();
    }
}

录屏演示
如果将volatile关键字去掉,线程切换一定次数后将不能感知到flag的变化,最开始能感知是线程启动时间差的原因。

等待/通知机制

等待通知机制是基于wait和notify方法来实现的,在一个线程内调用该线程锁对象的wait方法,线程将进入等待队列进行等待直到被通知或者被唤醒。

为什么要必须获取锁?
因为调用wait方法时,必须要先释放锁,如果没有持有锁将会抛出异常。

代码示例

/** * * @author wengyz * @version WaitDemo.java, v 0.1 2020-04-12 22:42 */
public class WaitDemo { 
   

    private static Object lock = new Object();
    private static  boolean flag = true;

    public static void main(String[] args) { 
   
        new Thread(new Runnable() { 
   
            @Override
            public void run() { 
   
                synchronized (lock){ 
   
                    while (flag){ 
   
                        try { 
   
                            System.out.println("wait start .......");
                            lock.wait();
                        } catch (InterruptedException e) { 
   
                            e.printStackTrace();
                        }
                    }

                    System.out.println("wait end ....... ");
                }
            }
        }).start();

        new Thread(new Runnable() { 
   
            @Override
            public void run() { 
   
                if (flag){ 
   
                    synchronized (lock){ 
   
                        if (flag){ 
   
                            lock.notify();
                            System.out.println("notify .......");
                            flag = false;
                        }

                    }
                }
            }
        }).start();
    }
}

wait流程原理图
在这里插入图片描述

join方式

join其实合理理解成是线程合并,当在一个线程调用另一个线程的join方法时,当前线程阻塞等待被调用join方法的线程执行完毕才能继续执行,所以join的好处能够保证线程的执行顺序,但是如果调用线程的join方法其实已经失去了并行的意义,虽然存在多个线程,但是本质上还是串行的,最后join的实现其实是基于等待通知机制的。
在这里插入图片描述

threadLocal方式

threadLocal方式的线程通信,不像以上三种方式是多个线程之间的通信,它更像是一个线程内部的通信,将当前线程和一个map绑定,在当前线程内可以任意存取数据,减省了方法调用间参数的传递。

扫码关注吧

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/34564.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注