相关阅读:
Java并发编程(一)知识地图
Java并发编程(三)可见性
Java并发编程(四)有序性
Java并发编程(五)创建线程方式概览
Java并发编程入门(六)synchronized用法
Java并发编程入门(七)轻松理解wait和notify以及使用场景
Java并发编程入门(八)线程生命周期
Java并发编程入门(九)死锁和死锁定位
Java并发编程入门(十)锁优化
Java并发编程入门(十一)限流场景和Spring限流器实现
Java并发编程入门(十二)生产者和消费者模式-代码模板
Java并发编程入门(十三)读写锁和缓存模板
Java并发编程入门(十四)CountDownLatch应用场景
Java并发编程入门(十五)CyclicBarrier应用场景
Java并发编程入门(十六)秒懂线程池差别
Java并发编程入门(十七)一图掌握线程常用类和接口
Java并发编程入门(十八)再论线程安全
Java并发编程入门(十九)异步任务调度工具CompleteFeature
Java并发编程入门(二十)常见加锁场景和加锁工具
一、一个小测验
并发情况下,下面两个类是否线程安全?
public class Counter {
private int count;
public void increase() {
count = count + 1;
}
public int getCount() {
return count;
}
}
public class Basket {
//Vector是线程安全的集合
Vector<Fruit> v = new Vector<Fruit>();
public void put(Fruit fruit) {
v.add(fruit);
}
public Fruit tackOut() throws Exception {
if (v.size() > 0) {
return v.remove(0);
} else {
throw new Exception("There is no fruit in basket.");
}
}
}
答案:以上两个类在并发情况下均不能保证线程安全。
二、线程安全和原子性
线程安全:当多个线程访问某个类时,这类始终都能表现出正确的行为,那么这个类是线程安全的。
原子性:一个或者多个操作在CPU执行的过程中不被中断的特性称为原子性。
而以上两个类不能保证操作原子性导致不能表现正确的行为,因此都不是线程安全的。
1.在类Counter中,以下代码实际执行了三个指令:
count = count + 1;
在多线程并发情况下由于线程切换会导致计算结果不正确。
注:图片参考Java并发编程实战
2.在类中的如下代码不是原子的,可能会导致抛出空指针异常和预期不符:
if (v.size() > 0) {
return v.remove(0);
}
三、修正
原子性可以通过加锁来解决,修正如下:
public class Counter {
private int count;
public synchronized void increase() {
count = count + 1;
}
/** 原子操作可不加同步关键字 */
public int getCount() {
return count;
}
}
public class Basket {
Vector<Fruit> v = new Vector<Fruit>();
/** 原子操作可不加同步关键字 */
public void put(Fruit fruit) {
v.add(fruit);
}
/** 加上synchronized关键字 */
public synchronized Fruit tackOut() throws Exception {
if (v.size() > 0) {
return v.remove(0);
} else {
throw new Exception("There is no fruit in basket.");
}
}
}
end.
<--阅过留痕,左边点赞 !