摘要:如何使多个线程同时访问一个对象,对象的更新同步:内存可见性

一、可见性

《java并发编程实战》第3章对象的共享

上面的程序会出现以下两种情况(1)由于reday的不可见性,对于不同线程来说。可能无法停止下来。(2)number会输出0,这个是因为重排序问题:即便在主函数里面ready=true是后赋值的,但是由于主线程更新number的值并没有同步,造成子线程获取不到更新的值,但是ready的值确更新了。这就造成了变量顺序的改变

二、失效数据

不使用同步,线程读取的是以前残留在用户缓存的值,失效数据会导致程序异常。考虑下面的同步

《java并发编程实战》第3章对象的共享

首先对于set方法使用同步,确保更新对于其他线程是可见的。这里为啥也要对获取get()进行同步关键字呢。这里我的思考就是使用synchronized会导致方法访问变量的时候总是去内核拿变量。而不是使用缓存。如果不使用可能会导致set的方法设置1的值没有办法被访问。

三、加锁与可见性

内置锁的作用,对于同一个锁保护的同步代码块,确保两个线程之间的操作是透明的。如果使用不同锁保护同步代码块,会导致在释放锁之前,另外一个线程读取的数据是失效值。所以访问所有共享变量需要在同一个锁上同步

四、volatile

volatile相当于同步更新,声明变量为共享变量。在另外一个线程处理的时候,总是从内核拿真正的值,而不是使用缓存的值。volatile是一种轻量级锁,使用volatile需要保证,对变量写入不依赖当前值:比如记录实时温度,true or false 运算结果等、

五、发布与逸出

原因:一个类保存了另一个类的引用。

this引用逸出:一个类构造函数中,包括了他成员变量的初始化。如果封装在构造函数中,可能会被其他线程拿到当前对象的事例,而实际上对象并没有构造完成。所以得出的结果也是错的。如图程序

《java并发编程实战》第3章对象的共享

解决方法就是,利用工厂模式,完成内部成员的初始化,才会发布这个对象的实例

《java并发编程实战》第3章对象的共享

六、线程封闭

原理:不共享数据,一个线程使用数据,拒绝其他线程的使用。典型就是JDBC,在Connection返回之前不会再分配给其他线程

1.Ad-hot线程封闭,简单介绍就是使用程序实现封闭,也就是自己实现单线程模式,子系统变为单线程子系统

2.栈封闭,就是使用局部变量,存在于栈中。在局部方法中创建对象且使对象逸出

3.ThreadLocal类。每个线程获取的都是变量的副本,他们是相同的,但是对于同一个线程的set会改变局部变量的值,get会拿到局部的最新值。

具体应用:比如缓冲区,共同使用,但是对于每个线程是独立的。ThreadLocal只是对于创建非常耗时的操作才有用

七、不可变对象

使用final确保每次设置了变量的值,就不会改变。原理:只允许一个线程修改他的值,其他线程无法修改。修改了值也是固定的

考虑下面的类

《java并发编程实战》第3章对象的共享

 

《java并发编程实战》第3章对象的共享a

红框中的语句是重点,通过每次重复创建不可变类维持线程安全。一旦创建就不可修改。但是笔者认为这会导致jvm堆内存不够,如果创建了太多对象。。

相关文章:

  • 2021-11-04
  • 2021-05-10
  • 2021-11-04
  • 2021-05-26
  • 2021-11-30
  • 2021-08-01
  • 2021-01-09
  • 2021-09-10
猜你喜欢
  • 2021-11-01
  • 2021-04-11
  • 2021-07-04
  • 2022-01-13
  • 2021-12-30
  • 2021-09-16
  • 2021-11-04
相关资源
相似解决方案