voliatle关键字

1.volatile关键字使用:

  多线程中存在私有堆栈中的值和公共堆栈中的值不同步的问题。什么意思呢?可能线程在一个地方修改了内存中变量的值,而其它地方线程却从私有堆栈中去读取不一致的变量值。关键字volatile 的主要作用是使在多个线程上可见。也就是,强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。

  • 线程的私有堆栈:

  • 读取公共内存:

强制从私有堆栈中取值的方法为JVM被设置为-server(不设置-server也是从私有堆栈中获取值)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package chapter2;
 
public class VolatileTest {
     
     
    static class RunThread extends Thread{
            private boolean isRunning = true;
 
        public boolean isRunning() {
            return isRunning;
        }
 
        public void setRunning(boolean isRunning) {
            this.isRunning = isRunning;
        }
         
        @Override
        public void run() {
            super.run();
            System.out.println("进入run 了");
            while (isRunning) {
                 
            }
            System.out.println("线程被停止了!");
        }
    }
     
    public static void main(String[] args) {
        try {
            RunThread runThread = new RunThread();
            runThread.start();
            Thread.sleep(1000);
            runThread.setRunning(false);
            System.out.println("已经赋值为false");
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
 
}

运行结果:

进入run 了
已经赋值为false
永远不会打印线程被停止了!

volatile private boolean isRunning = true;//强制从公共堆栈中取得变量的值

运行结果:

进入run 了
已经赋值为false
线程被停止了!

非原子性验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package chapter2;
 
public class VolatileThread extends Thread{
    volatile public static int count;
    private static void addCount() {
        for(int i=0;i<100;i++) {
            count++;
        }
        System.out.println("Thread:"+currentThread().getName()+"--count:"+count);
    }
     
    @Override
    public void run() {
        super.run();
        addCount();
    }
 
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package chapter2;
 
public class VolatileTest {
     
    public static void main(String[] args) {
        VolatileThread[] volatileThreads = new VolatileThread[100];
        for (int i = 0; i < 100; i++) {
            volatileThreads[i] = new VolatileThread();
        }
         
        for(int i=0;i<100;i++) {
            volatileThreads[i].start();
        }
    }
 
}

 运行结果:

Thread:Thread-84--count:8683
Thread:Thread-88--count:8863
Thread:Thread-89--count:8863
Thread:Thread-87--count:8963
Thread:Thread-90--count:9063
Thread:Thread-92--count:9163
Thread:Thread-97--count:9663
Thread:Thread-96--count:9563
Thread:Thread-98--count:9763
Thread:Thread-95--count:9863
Thread:Thread-93--count:9463
Thread:Thread-94--count:9363
Thread:Thread-91--count:9263
Thread:Thread-99--count:9963

非原子性的原因:

  • read 和 load 阶段:从主存复制变量到当前线程工作内存。
  • use 和 assign 阶段:执行代码,改变共享变量值。
  • store 和 write 阶段:用工作内存数据刷新主存对应变量的值。

   在多线程环境中,use和assign 是多次出现的,但这一操作并不是原子性,也就是说在read和load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,也就是私有内存和公有内存的变量不同步,所以计算出来的结果和预期不一样,也就出现了非线程安全的问题。

2.使用原子类进行i++操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package chapter2;
 
import java.util.concurrent.atomic.AtomicInteger;
 
public class VolatileThread extends Thread{
    private AtomicInteger count = new AtomicInteger(0);
    private void addCount() {
        for(int i=0;i<10000;i++) {
            System.out.println(count.incrementAndGet());
        }
    }
     
    @Override
    public void run() {
        super.run();
        addCount();
    }
 
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package chapter2;
 
public class VolatileTest {
     
    public static void main(String[] args) {
        try {
            VolatileThread volatileThread = new VolatileThread();
            Thread t1 = new Thread(volatileThread);
            t1.start();
            Thread t2 = new Thread(volatileThread);
            t2.start();
            Thread t3 = new Thread(volatileThread);
            t3.start();
            Thread t4 = new Thread(volatileThread);
            t4.start();
            Thread t5 = new Thread(volatileThread);
            t5.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
 
}

运行结果:

49990
49991
49992
49993
49994
49995
49996
49997
49998
49999
50000

成功累加到50000!

posted @   断了线的风筝~  阅读(374)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示