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关键字进行并发控制。