本视频是解读性视频,所以希望您已经看过了本知识点的内容,并且编写了相应的代码之后,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
5分43秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项) 步骤 1 : 原子性操作概念 步骤 2 : AtomicInteger 步骤 3 : 同步测试 步骤 4 : 练习-使用AtomicInteger来替换Hero类中的synchronized 步骤 5 : 答案-使用AtomicInteger来替换Hero类中的synchronized
所谓的原子性操作即不可中断的操作,比如赋值操作
int i = 5; 原子性操作本身是线程安全的 但是 i++ 这个行为,事实上是有3个原子性操作组成的。 步骤 1. 取 i 的值 步骤 2. i + 1 步骤 3. 把新的值赋予i 这三个步骤,每一步都是一个原子操作,但是合在一起,就不是原子操作。就不是线程安全的。 换句话说,一个线程在步骤1 取i 的值结束后,还没有来得及进行步骤2,另一个线程也可以取 i的值了。 这也是分析同步问题产生的原因 中的原理。 i++ ,i--, i = i+1 这些都是非原子性操作。 只有int i = 1,这个赋值操作是原子性的。
JDK6 以后,新增加了一个包java.util.concurrent.atomic,里面有各种原子类,比如AtomicInteger。
而AtomicInteger提供了各种自增,自减等方法,这些方法都是原子性的。 换句话说,自增方法 incrementAndGet 是线程安全的,同一个时间,只有一个线程可以调用这个方法。 package multiplethread;
import java.util.concurrent.atomic.AtomicInteger;
public class TestThread {
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicI =new AtomicInteger();
int i = atomicI.decrementAndGet();
int j = atomicI.incrementAndGet();
int k = atomicI.addAndGet(3);
}
}
package multiplethread; import java.util.concurrent.atomic.AtomicInteger; public class TestThread { public static void main(String[] args) throws InterruptedException { AtomicInteger atomicI =new AtomicInteger(); int i = atomicI.decrementAndGet(); int j = atomicI.incrementAndGet(); int k = atomicI.addAndGet(3); } }
分别使用基本变量的非原子性的++运算符和 原子性的AtomicInteger对象的 incrementAndGet 来进行多线程测试。
测试结果如图所示 package multiplethread;
import java.util.concurrent.atomic.AtomicInteger;
public class TestThread {
private static int value = 0;
private static AtomicInteger atomicValue =new AtomicInteger();
public static void main(String[] args) {
int number = 100000;
Thread[] ts1 = new Thread[number];
for (int i = 0; i < number; i++) {
Thread t =new Thread(){
public void run(){
value++;
}
};
t.start();
ts1[i] = t;
}
//等待这些线程全部结束
for (Thread t : ts1) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.printf("%d个线程进行value++后,value的值变成:%d%n", number,value);
Thread[] ts2 = new Thread[number];
for (int i = 0; i < number; i++) {
Thread t =new Thread(){
public void run(){
atomicValue.incrementAndGet();
}
};
t.start();
ts2[i] = t;
}
//等待这些线程全部结束
for (Thread t : ts2) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.printf("%d个线程进行atomicValue.incrementAndGet();后,atomicValue的值变成:%d%n", number,atomicValue.intValue());
}
}
在给Hero的方法加上修饰符synchronized 这个知识点中,通过给hurt和 recover方法加上synchronized来达到线程安全的效果。
这一次换成使用AtomicInteger来解决这个问题 提示:int基本类型对应的是AtomicInteger,但是float基本类型没有对应的AtomicFloat。 所以在这个练习中,把hp改为AtomicInteger即可。
HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
|