架构师养成记--4.volatile关键字

volatile修饰的变量可在多个线程间可见。

如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本。

 

 1 public class RunThread extends Thread{
 2 
 3     private volatile boolean isRunning = true;
 4     private void setRunning(boolean isRunning){
 5         this.isRunning = isRunning;
 6     }
 7     
 8     public void run(){
 9         System.out.println("进入run方法..");
10         int i = 0;
11         while(isRunning == true){
12             //..
13         }
14         System.out.println("线程停止");
15     }
16     
17     public static void main(String[] args) throws InterruptedException {
18         RunThread rt = new RunThread();
19         rt.start();
20         Thread.sleep(1000);
21         rt.setRunning(false);
22         System.out.println("isRunning的值已经被设置了false");
23     }
24     
25     
26 }
View Code

那么如何达到预期效果让子线程停止呢?那就是变量isRunning使用volatile修饰,原理如下图

 

 

 需要注意的一点是,volatile关键字修饰的变量只有可见性,没有原子性。如下代码,如果使用第九行代码的话最终打印结果不是10000

 1 import java.util.concurrent.atomic.AtomicInteger;
 2 
 3 /**
 4  * volatile关键字不具备synchronized关键字的原子性(同步)
 5  * @author alienware
 6  *
 7  */
 8 public class VolatileNoAtomic extends Thread{
 9     //private static volatile int count;
10     private static AtomicInteger count = new AtomicInteger(0);
11     private static void addCount(){
12         for (int i = 0; i < 1000; i++) {
13             //count++ ;
14             count.incrementAndGet();
15         }
16         System.out.println(count);
17     }
18     
19     public void run(){
20         addCount();
21     }
22     
23     public static void main(String[] args) {
24         
25         VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
26         for (int i = 0; i < 10; i++) {
27             arr[i] = new VolatileNoAtomic();
28         }
29         
30         for (int i = 0; i < 10; i++) {
31             arr[i].start();
32         }
33     }
34     
35     
36     
37     
38 }
View Code

那么如何才能有原子性呢?可以对对象进行AtimicInteger  修饰

 

多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 import java.util.concurrent.atomic.AtomicInteger;
 4 
 5 public class AtomicUse {
 6 
 7     private static AtomicInteger count = new AtomicInteger(0);
 8     
 9     //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
10     /**synchronized*/
11     public synchronized int multiAdd(){
12             try {
13                 Thread.sleep(100);
14             } catch (InterruptedException e) {
15                 e.printStackTrace();
16             }
17             count.addAndGet(1);
18             count.addAndGet(2);
19             count.addAndGet(3);
20             count.addAndGet(4); //+10
21             return count.get();
22     }
23     
24     
25     public static void main(String[] args) {
26         
27         final AtomicUse au = new AtomicUse();
28 
29         List<Thread> ts = new ArrayList<Thread>();
30         for (int i = 0; i < 100; i++) {
31             ts.add(new Thread(new Runnable() {
32                 @Override
33                 public void run() {
34                     System.out.println(au.multiAdd());
35                 }
36             }));
37         }
38 
39         for(Thread t : ts){
40             t.start();
41         }
42 
43 
44     
45         
46 
47         
48     }
49 }
View Code

 

posted on 2016-12-04 23:43  司广孟  阅读(394)  评论(0编辑  收藏  举报

导航