在阅读了《JAVA 并发编程实战. PDF》之后, 突感恐慌, 怎么就这么容易出现线程并发的问题, 那我以前写的代码, 是不是有很多 bug 啊. 深刻反思之后, 发现果不其然 (取反吐舌头)~
一开始学编程的时候, 都会遇到线程安全的 Map, 线程安全的 List, 然后去百度了一波, 然后得到了一些结果, 比如说:
1,ArrayBlockingQueue: 用锁去控制并发, 所以在一些操作队列的方法体里面, 都会有对锁的操作, 比如常用的 put(E e),take():
2,Hashtable: 在存取数据的时候, 通过 synchronized 关键字控制并发, 比如 get(Object key),put(K key, V value).
3,ConcurrentHashMap: 这个大家百度得到的答案, 肯定是高效率的, 线程安全的 Map 结构, 使用 volatile 关键字定义原子属性, 用此关键字定义的属性 xxxxxxxxxx(此处省略, 大家可自行百度~),ConcurrentHashMap 使用一个 table 属性存放数据.
4,ThreadLocalMap: 这个大家比较少见, 使用 ThreadLocal 控制线程安全, 其 set 与 get 方法都是用 ThreadLocal<?> 作为参数, 即与线程绑定的变量.
[重点]
1, 那为什么要用以上的这四种手段去控制并发操作呢?
2, 为什么平常时我们自己定义的对象, 几乎未使用这些方式的去控制线程安全呢?
3, 什么情况下需要控制某个对象的在多线程环境下的安全性呢?
接下来就按照我自己的理解一一解答~
首先, 第一点毋庸置疑, 线程安全是必须的, 如果在多线程环境先使用了非线程安全的类或者未将线程安全的类正确使用, 都有可能会线程并发错误等问题, 换句话说, 可能落库的数据就不对啦 (偶发, 不容易查, 所以各位即将转型 java 的小伙伴得注意啦).
关于第二点, 有这几种情况,
1, 应用本身是单线程的应用, 不需要考虑多线程.
2, 其次可能是你写的代码, 本身就是线程安全的. 如果对象里面未定义静态属性, 且此对象也未作为静态属性定义在其他对象中, 那么这个类一定可以放心使用.
3, 第二个是, 你的代码可能会出 bug, 因为是偶发的, 只是没有出现而已啦.
众所周知的是, 线程安全问题, 是因为多个线程在同一时刻会访问同一个变量, 所以只需要避免此问题即可. 那么在编码的过程中如何保证呢? 以我的经验来看, 用以下方式即可~
1, 不在类里面定义可变的静态属性, 这个属性包含类的所有属性里面的属性.
2, 如果一定要定义静态变量, 那么这个静态变量的 setter 方法要加同步处理, 或者用 ThreadLoca<T > 定义, 一般情况下建议用 ThreadLocal 就好了, 简单实用, 如果想弄清楚 java 的多线程编程, 那多用用同步也不对, 毕竟多踩坑才会有成长 (但千万别在生产环境踩啊)
说到这里呢, 第三点其实已经明确了:
在定义对象的时候, 不用随意使用可变的静态变量, 使用了静态变量就要保证它的 setter 方法是线程安全的, 总不能创建了它, 就不考虑它的死活了, 它在同一个时刻要变成这么多值, 它也很无奈啊, 就不知道要变成啥, 它也不敢问, 所以随便变一个值了, 当然, 这个值可能就不是你预期的了.
以上内容纯手工编写, 若有谬误, 欢迎指正~
来源: http://www.bubuko.com/infodetail-3097391.html