第78条 同步访问共享的可变数据
- 同步不仅可以阻止一个线程看到对象处于不一致的状态之中,它还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护的之前所有的修改效果
- 读取一个非
long
或double
类型的变量,可以保证返回的值是某个线程保存在该变量中的,即使多个线程在没有同步的情况下并发地修改这个变量也是如此 - 不要使用
Thread.stop
。要在一个线程终止另一个线程,建议的做法是让第一个线程设置一个boolean
域,这个域一开始为false
,但是可以通过第二个线程设置为true
,这样来表示第一个线程要终止自己 - 除非读和写操作都被同步,否则就无法保证同步会起作用
- 虽然 volatile 修饰符不执行互斥访问,但它可以保证任何一个线程在读取该域的时候都将看到最近刚刚被写入的值
- 自增操作符(++)不是原子的,如果想要使用++的效果,推荐使用
AtomicLong
- 尽可能将可变数据限制在单个线程中
- 让一个线程在短时间内修改一个数据对象,然后与其他线程共享,这是可以接受的
- 当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步
思考
- 对于多线程场景,线程对共享变量的操作都是将数据拷贝到自己的工作内存操作后回写到主内存中,所以直接赋值也会造成同步延迟现象,这也是
volatile
关键字的功能之一 -
long
和double
都是64位的,相当于需要两次32位的操作。Java中除了long
和double
以外的基本数据类型和所有引用赋值都是原子操作 -
volatile
的两个功能:- 会将线程的修改同步到主内存
- 不会发生指令重排,保证命令的有序性