关键字volatile的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
1.先做一个实验:
* 源码:
public class RunThread extends Thread{
private boolean isRunning=true;
public boolean isRunning() {
return isRunning;
}
public void setRunning(boolean running) {
isRunning = running;
}
@Override
public void run() {
System.out.println("进入run了");
while(isRunning == true){
}
System.out.println("线程被停止了!");
}
}
public class Run {
public static void main(String[] args){
RunThread thread=new RunThread();
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.setRunning(false);
System.out.println("已经赋值为false");
}
}
运行该代码,发现根本不会停止的,什么原因呢?
在启动RunThread.java线程是,变量isRunning=true;存在与公共堆栈及线程的私有堆栈中。
为了运行的效率,线程一直在私有堆栈中取得isRunning的值是true,而更新的却是公共堆栈中
的isRunning变量值false.所以一直就是死循环的状态。
改成:
volatile private boolean isRunning=true;
就可以了,volatile关键字的作用就是当线程访问isRunning这个变量是,强制性从公共堆栈中进行取值。
2. 关键字synchronized和volatile进行比较:
* 关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比 synchronized要好,并且 volatile只能
修饰于变量,而 synchronized可以修饰方法,以及代码块。
* 多线程访问volatile不会发生阻塞,而 synchronized会发生阻塞
* volatile能保证数据的可见性,但不能保证原子性;而 synchronized可以保证原子性,也可以间接保证可见性,
因为它会将私有内存和公有内存中的数据做同步、
* 关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。
3. volatile 非原子的特性
* 案例说明volatile不具有原子性和同步性
eg
public class MyThread extends Thread {
volatile public static int count;
private static void addCount() {
count++;
System.out.println("count=" + count);
}
@Override
public void run() {
addCount();
}
}
public class Run {
public static void main(String[] args){
MyThread[] myThreads=new MyThread[100];
for(int i=0;i<100;i++){
myThreads[i]=new MyThread();
}
for(int i=0;i<100;i++){
myThreads[i].start();
}
}
}
运行后发现,好多变量出现了好多次哦,这是因为i++不是原子性的,分为三步:
* 从内存中取出i的值
* 计算i的值
* 将i的值写到内存中
3. synchronized代码块有volatile同步的功能
* 关键字synchronized可以使多个线程访问同一个资源具有同步性,而且它还具有将线程工作内存中的
私有变量与公共内存中的变量同步的功能
eg:
public class Service {
private boolean isContinueRun=true;
public void runMethod(){
while(isContinueRun==true){
}
System.out.println("停下来了!");
}
public void stopMethod(){
isContinueRun=false;
}
}
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service){
super();
this.service=service;
}
@Override
public void run() {
service.runMethod();
}
}
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service){
super();
this.service=service;
}
@Override
public void run() {
service.stopMethod();
}
}
public class Run {
public static void main(String[] args){
Service service=new Service();
ThreadA a=new ThreadA(service);
a.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadB b=new ThreadB(service);
b.start();
System.out.println("已经发起停止的命令了!");
}
}
该代码并不能停止,具体前面说了,没有可见性,前面是用volatile实现的,现在用synchronized
Service代码做如下更改:
public class Service {
private boolean isContinueRun=true;
public void runMethod(){
String anyString=new String();
while(isContinueRun==true){
synchronized (anyString){
}
}
System.out.println("停下来了!");
}
public void stopMethod(){
isContinueRun=false;
}
}
现在可以了,s关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法或某一个代码块。
它包含两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还
可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。(书上原话= =)
在我的理解,如果锁加在isContinueRun上是可以理解的,为了同步,肯定会强制用公共堆栈,但是加在anyString上= =,
anyString被强制公共堆栈并没有什么卵用= =,在我的理解是,加了synchronized关键词,在未执行到指定代码之前,
虚拟机并不知道锁在哪个对象上,为了让锁的对象永远保持一个,保证同步,只要类中出现synchronized关键字,就把
所有对象的存取指定在公共堆栈。(个人看法)。
多线程 volatile关键字
原创
©著作权归作者所有:来自51CTO博客作者无名同学的原创作品,请联系作者获取转载授权,否则将追究法律责任
上一篇:java8 用流收集数据
下一篇:n对括号组合的所有情况
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
多线程与volatile关键字
文章目录1.多线程与高并发(四)volatile关键字2.java多线程编程之volatile和CA
多线程 高并发 java多线程编程