1.正常编码i++
(1)代码示例
public class TestThread {
private static int val = 0;
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
new Thread(new Runnable(){
public void run() {
getNext();
try {
/*为了突出线程效果*/
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
public static void getNext() {
val++;
System.out.println(val);
}
}
(2)执行结果(部分)
2
3
4
5
6
7
8
9
2
执行结果中出现了两个2,线程非安全
2.优化步骤1,使用volatile
(2)代码示例
public class TestThread {
private volatile static int val = 0;
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
new Thread(new Runnable(){
public void run() {
getNext();
try {
/*为了突出线程效果*/
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
public static void getNext() {
val++;
System.out.println(val);
}
}
(2)执行结果(部分)
2
2
3
4
5
6
仍然出现线程不安全的情况,这是为什么?
因为i++是由三个独立的步骤组成
①读取i ②i+1 ③将增值加后的i赋值给之前的i
由上三步可知,i++并非原子操作,线程不安全
3.优化步骤2,使用synchronized
(1)代码示例
public class TestThread {
private volatile static int val = 0;
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
new Thread(new Runnable(){
public void run() {
getNext();
try {
/*为了突出线程效果*/
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
public static synchronized void getNext() {
val++;
System.out.println(val);
}
}
(2)执行结果(部分)
1
2
3
4
5
6
结果正常,线程安全
4.步骤优化4,使用原子类
(1)代码示例
public class TestThread {
private static AtomicInteger val = new AtomicInteger(0);
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
new Thread(new Runnable(){
public void run() {
getNext();
try {
/*为了突出线程效果*/
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
public static void getNext() {
int result = val.incrementAndGet();
System.out.println(result);
}
}
(2)执行结果(部分)
1
2
3
4
5
6
结果正常,线程安全
总结
i++操作是由三个对立的操作组成,线程非安全,可使用原子类或synchronized关键字进行并发控制。
版权声明:本文为ly853602原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。