多线程学习笔记(十二)

 2023-09-05 阅读 110 评论 0

摘要:2019独角兽企业重金招聘Python工程师标准>>> volatile的作用是使变量在多个线程间可见 1.死循环 public class PrintInfo implements Runnable {private boolean statu = true;public boolean isStatu() {return statu;}public void setStatu(boolean statu) {t

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

volatile的作用是使变量在多个线程间可见

1.死循环

public class PrintInfo implements Runnable {private boolean statu = true;public boolean isStatu() {return statu;}public void setStatu(boolean statu) {this.statu = statu;}public void printInfo() {try {while(statu  == true){System.out.println("The Thread Name Is " + Thread.currentThread().getName());Thread.sleep(1000);Thread.sleep(1000);}} catch (Exception e) {e.printStackTrace();}}@Overridepublic void run() {printInfo();}
}
public class Run {public static void main(String[] args){
PrintInfo printInfo = new PrintInfo();
printInfo.printInfo();
System.out.println("Try To Stop The Thread");
printInfo.setStatu(false);

}
}

运行结果:

 

2.解决同步死循环

将一中的代码Run类修改为

public class Run {public static void main(String[] args) throws InterruptedException {PrintInfo printInfo = new PrintInfo();Thread thread = new Thread(printInfo);thread.start();Thread.sleep(1000);System.out.println("Try To Stop The Thread");printInfo.setStatu(false);}
}

运行结果:

但当上面的实例代码运行在 -server服务器模式的64位的JVM上时,会出现死循环,解决的办法是使用volatile关键字.

volatile关键字的作用是强制从公共堆栈中取得变量的值,而不是从线程使用数据栈中取得变量的值

 

3.解决异步死循环

将1中的代码PrintInfo修改为

public class PrintInfo implements Runnable {volatile private boolean statu = true;public boolean isStatu() {return statu;}public void setStatu(boolean statu) {this.statu = statu;}public void printInfo() {try {while(statu  == true){System.out.println("The Thread Name Is " + Thread.currentThread().getName());Thread.sleep(1000);}} catch (Exception e) {e.printStackTrace();}}@Overridepublic void run() {printInfo();}
}

运行结果:

 

4.关键字synchronized与volatile的区别

使用volatile关键字增加了实例变量在多个线程之间的可见性,但是volatile关键字的缺点是不支持原子性.

    1).关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,二synchronized可以修饰方法,以及代码块.随着JDK新版本的发布,synchronized关键字的执行效率得到很大提升,在开发中使用synchronized关键字的比例还是比较大.

    2).多线程访问volatile不会发生阻塞,二synchronized回出现阻塞

    3).volatile能保证数据的可见性.但不能保证原子性,而synchronized可以保证原子性,也可以间接保证可见性,以内他会将使用内存和公共内存中的数据做同步.

    4).关键字volatile解决的是变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性,

线程安全包含原子性和可见性两个方面,JAVA的同步机制都是围绕这两个方面来确保线程安全的.

 

5.volatile的非原子特性

public class VolatileThread extends Thread{volatile public static int count ;private static void sumCount(){for(int i = 0 ; i < 10 ; i ++){count ++;}System.out.println("count = " + count);}@Overridepublic void run() {sumCount();}
}
public class Run {public static void main(String[] args){VolatileThread[] volatileThreads = new VolatileThread[100];for(int i = 0 ; i < 10 ; i ++){volatileThreads[i] = new VolatileThread();}for(int i = 0 ; i < 10 ; i ++){volatileThreads[i].start();}}
}

运行结果:

 

更改VolatileThread类代码为:

public class VolatileThread extends Thread{volatile public static int count ;synchronized private static void sumCount(){for(int i = 0 ; i < 10 ; i ++){count ++;}System.out.println("count = " + count);}@Overridepublic void run() {sumCount();}
}

运行结果:

 

关键字volatile主要使用的场合是在多个线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量时可以获取最新值使用.

关键字volatile提示线程每次从共享内存中读取变量,而不是从私有内存中读取,这样就保证了同步数据的可见性,但需要注意的是:如果修改实例变量中的数据,比如i++,这样的操作其实并不是一个院子操作,也就是非线程安全的.

表达式i++的操作不走分解如下:

    1).从内存中获取i的值,

    2).计算i的值,

    3).将计算后的值存储到内存中.

如果在第二步时,另一个线程也修改了i的值,那么这个时候就会出现脏数据,解决的办法就是使用synchronized关键字,所以volatile本身并不处理数据的原子性,而是强制对数据的读写及时影响到主内存.

转载于:https://my.oschina.net/scymore/blog/746362

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/986.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息