线程之间为什么要通信?
通信的目的是为了更好的协作,无论线程是交替执行还是中继执行,都需要进行通信通知。 那么java线程是如何通信的,大致有以下4种方式。
Java线程的通信方式volatile
等待/通知机制
联合方式
热带局域网
volatile关键字方式
volatile有两大特性。 一个是可见性,另一个是有序性,禁止对命令进行排序。 其中可见性是指允许线程之间的通信。
volatile语义保证线程的可见性有两个原则,所有volatile限定变量都必须在线程更改后立即刷新到主内存
所有volatile限定变量都必须重新读取主内存的值,然后才能使用
电压保证可见性原理图
工作存储器2可以识别出工作存储器1更新a的值取决于总线。 工作存储器1在通过更新值的主存储器时必须通过总线。 总线通知其他线程该值已更改,其他线程主动读取并更新主内存中的值。
样品
//*
*
* @author wengyz
* @version VolatileDemo.java,v 0.1 2020-04-12 22:09
*/
公共类卷演示{
私密性统计信息布尔标志=true;
publicstaticvoidmain (字符串[ ] args ) {
新线程(新运行) )。
@Override
公共void run (}
while (真)。
if (标志) {
system.out.println(trunon );
flag=false;
}
}
}
().start );
新线程(新运行) )。
@Override
公共void run (}
while (真)。
if (! flag ) {
系统. out.println (trun off );
标志=true;
}
}
}
().start );
}
} https://www.zhi Hu.com/video/1232813261310992384
如果删除volatile关键字,则线程切换一定次数后将无法感知flag的变化,而首先感知到的则是线程启动时间差的原因。
等待/通知机制
等待通知机制基于wait和notify方法实现,在线程中调用该线程锁定的wait方法,并在通知或唤醒之前进入等待队列。
为什么一定要拿到锁?
调用wait方法时,必须首先解除锁定,因此如果没有锁定,则会抛出异常。
代码示例
//*
*
* @author wengyz
* @version WaitDemo.java,v 0.1 2020-04-12 22:42
*/
公共班级等待演示{
私密性staticobjectlock=new object (;
私有静态布尔标志=true;
publicstaticvoidmain (字符串[ ] args ) {
新线程(新运行) )。
@Override
公共void run (}
同步(锁定) {
while(flag ) {
try {
system.out.println(waitstart……);
lock.wait (;
} catch (互联互通) )
e .打印堆栈跟踪(;
}
}
system.out.println(waitend…… . );
}
}
().start );
新线程(新运行) )。
@Override
公共void run (}
if (标志) {
同步(锁定) {
if (标志) {
lock.notify (;
system.out.println('notify…… . );
flag=false;
}
}
}
}
().start );
}
}
wit流程原理图
联合方式
join其实被合理地理解为线程整合。 在一个线程上调用另一个线程的连接方法时,当前线程将等待调用连接方法的线程执行完毕后继续运行。 因此,join的优点可以保证线程的执行顺序,但调用线程的join方法实际上会失去并行意义。 虽然存在多个线程,但本质上是串联的。 最后一个join实现基于等待通知机制。
热局部方式
threadLocal方式的线程通信不像上述三种方式那样是多个线程之间的通信,而是像线程内部的通信,将当前线程和一个map结合起来,从而可以在当前线程内任意访问数据,方法调用之间的参数通信
来源公众号:有趣的程序员