java多线程Synchronized实现可见性原理解析

网友投稿 367 2022-09-11


java多线程Synchronized实现可见性原理解析

Synchronized实现可见性原理

可见性

要实现共享变量的可见性,必须保证两点:

线程修改后的共享变量值能够及时从工作内存刷新到主内存中

其他线程能够及时把共享变量的最新值从主内存更新到自己的工作内存中

java语言层面支持的可见性的实现方式

synchronized

volatile

synchronized实现可见性

synchronized能够实现:

原子性(同步)

可见性

JMM关于synchronized的两条规定:

1.线程解锁前,必须把贡献变量的最新值刷新到主内存中

2.线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要同一把锁)

线程解锁前对共享变量的修改在下次加锁时对其他线程可见

线程执行互斥代码的过程

获取互斥锁

清空工作内存

从主内存拷贝变量的最新副本到工作内存

执行代码

将更改后的共享变量的值刷新到主内存

释放互斥锁

重排序:

代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做得优化

编译器优化的重排序(编译器优化)

指令级并行重排序(处理器优化)

内存系统的重排序(处理器优化)

as-if-serial

as-if-serial:无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致(Java编译器、运行时和处理器都会保证Java在单线程下遵循as-if-serial语义)

public class SynchronizedTest {

/**

* 共享变量

*/

private boolean ready = false;

private int result = 0;

private int number = 1;

/**

* 写操作

*/

public void write(){

ready = true;//1.1

number = 2;//1.2

}

/**

* 读操作

*/

public void read(){

if(ready){//2.1

result=number*3;//2.2

}

System.out.println("result的值为:"+result);

}

/**

* 内部线程类

*/

private class ReadWriteThread extends Thread{

//根据构造方法中传入的flag参数,确定线程执行读操作还是写操作

private boolean flag;

public ReadWriteThread(boolean flag){

this.flag=flag;

}

@Override

public void run() {

if(flag){

//构造方法中传入true,执行写操作

write();

}else{

//构造方法中传入false,执行读操作

read();

}

}

}

public static void main(String[] args) {

SynchronizedTest synchronizedTest = new SynchronizedTest();

//启动线程执行写操作

synchronizedTest.new ReadWriteThread(true).start();

//启动线程执行读操作

synchronizedTest.new ReadWriteThread(false).start();

}

}

导致共享变量在线程间不可见的原因

1.线程的交叉执行

eg:上述程序执行步骤为1.1-》2.1-》2.2-》1.2

eg:上述程序执行步骤为1.2-》2.1-》2.2-》1.1

2.重排序结合线程交叉执行

eg: 2.1和2.2重排序后

int mid = number*3;

if(ready){

result=mid;

}

共享变量更新后的值没有在工作内存与主内存间及时更新

安全性代码

public class SynchronizedTest {

/**

* 共享变量

*/

private boolean ready = false;

private int result = 0;

private int number = 1;

/**

* 写操作

*/

public synchronized void write(){

ready = true;//1.1

number = 2;//1.2

}

/**

* 读操作

*/

public synchronized void read(){

if(ready){//2.1

result=number*3;//2.2

}

System.out.println("resuhttp://lt的值为:"+result);

}

/**

* 内部线程类

*/

private class ReadWriteThread extends Thread{

//根据构造方法中传入的flag参数,确定线程执行读操作还是写操作

private boolean flag;

public ReadWriteThread(boolean flag){

this.flag=flag;

}

@Override

public void run() {

if(flag){

//构造方法中传入true,执行写操作

write();

}else{

//构造方法中传入false,执行读操作

read();

}

}

}

public static void main(String[] args) {

SynchronizedTest synchronizedTest = new SynchronizedTest();

//启动线程执行写操作

synchronizedTest.new ReadWriteThread(true).start();

//启动线程执行读操作

synchronizedTest.new ReadWriteThread(false).start();

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:观点 | 直播乱象背后的雪梨枪与东北二嫂,除了色情女主播还有什么出路?(观点人民网)
下一篇:观点 | 直播乱象背后的雪梨枪与东北二嫂,除了色情女主播还有什么出路?(观点地产)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~