JUC并发编程 -- 常见的线程安全类 & 线程安全类方法的组合 & 不可变类线程安全性
Posted Z && Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 -- 常见的线程安全类 & 线程安全类方法的组合 & 不可变类线程安全性相关的知识,希望对你有一定的参考价值。
1.常见线程安全类
- String
- Integer
- StringBuffer
- Random
- Vector
- Hashtable
- java.util.concurrent 包下的类
这里说它们是线程安全的是指,多个线程调用它们同一个实例的某个方法时,是线程安全的。也可以理解为:
示例代码:
Hashtable table = new Hashtable();
new Thread(()->{
table.put("key", "value1");
}).start();
new Thread(()->{
table.put("key", "value2");
}).start();
查看put方法源码:
分析:
虽然加了put方法中许多行代码,但是由于加了synchronized关键字,所以方法内部代码的执行不会被线程的上下文切换影响
小结:
- 它们的每个方法是原子的
- 但注意它们多个方法的组合不是原子的,见后面分析:
2. 线程安全类方法的组合
分析下面的代码是否线程安全?
/*
代码意图: 如果table为空,则插入一个元素,且最多也只有一个元素
*/
Hashtable table = new Hashtable();
// 线程1,线程2
if( table.get("key") == null) {
table.put("key", value);
}
答案:否。虽然get方法和put方法都加了synchronized关键字,但是这样只可以保证get和put方法内部的代码是原子性的,但是get和put方法在一起运行里面代码的执行顺序还是会受到线程上下文切换的影响。
图解分析:
图解说明:
这样就在table里面加了2条数据,违反了程序的意图
3. 不可变类线程安全性
- String、Integer 等都是不可变类(只可以进行读的操作),因为其内部的状态不可以改变,因此它们的方法都是线程安全的。
- 有同学或许有疑问,String 有 replace,substring 等方法【可以】改变值啊,那么这些方法又是如何保证线程安全的呢?
解答以 substring 方法为例子,其余的方法类似:
虽然没有加上synchronized关键字,但是方法内部的代码并没有对原来的资源进行操作,而是返回一个新的资源(如果截取的字符串和原来的字符串不相同,就返回一个新的字符串对象new String())
以上是关于JUC并发编程 -- 常见的线程安全类 & 线程安全类方法的组合 & 不可变类线程安全性的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 共享模式之工具 JUC 线程安全的集合类 -- 线程安全的集合类概述
JUC并发编程 -- 变量的线程安全问题(成员变量 & 静态变量 & 局部变量 & 开闭原则 & 理解JDK 中 String 类的实现)