Java并发的处理也算是老生常谈的一个问题,处理方法很多,但是一旦出现差池,后果也是相当严重,所以还是得好好补补,之前也是模糊了解而已,这段时间静下心来学习,也算是初有成见。
这里我就来说说Java并发的三种处理方式
1. volatile修饰共享变量
2. ThreadLocal操作共享数据
3. synchronize锁操作共享变量
使用场景:
-
volatile
多线程情况下 :一个线程修改共享变量,多个线程读取,举例:volatile修饰变量作为线程停止的标识符。
注意:
如果修改操作是基于当前值的时候就不能使用volatile,就比如i++;因为volatile虽然保证禁止重排序,但是并不是原子性操作,当最后写回主内存之前会出现问题。
具体参考:(这两篇看完基本就懂volatile了,很精辟)
https://www.jianshu.com/p/ac42412fa0cc
https://www.cnblogs.com/churao/p/8494160.html -
ThreadLocal
牺牲空间,创建额外的空间来存储共享变量的副本,线程内访问副本,互不影响。
每一个 Thread 都有一个 ThreadLocalMap ,这个 Map 以 ThreadLocal 对象为键,以要保存的线程局部变量为值。这样就做到了为每个线程保存不同的副本。
目的是将共享变量转变为 “线程局部变量”,相当于将共享变量分配给并发的线程,线程内操作变量,互不影响。举例spring中访问数据库需要使用模板类,用的是同一个连接资源,照例来说只能供一个线程使用,但是通过ThreadLocal即可实现多线程并发,每个线程内部都维系了一个同一个连接资源的副本。
具体参考:(也是一篇神文,包懂)
https://www.iteye.com/topic/1123824 -
synchronize
这个也是最常用的,直接锁住,牺牲时间,同一时刻只有一个线程可以访问。
最后总结:
- volatile 是为了保证资源被多个线程并发正确操作。(可见性,禁止重排序)
- ThreadLocal是为了保证资源不被多线程同时操作。(牺牲空间)
- synchronize是为了多线程下 同一时刻只有一个线程操作资源。(牺牲时间,保证原子性)