多线程学习笔记(十二)

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();
        }
    }

    @Override
    public 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.解决同步死循环ide

将一中的代码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);
    }
}

运行结果:this

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

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

 

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();
        }
    }

    @Override
    public 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);
    }

    @Override
    public 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);
    }

    @Override
    public void run() {
        sumCount();
    }
}

运行结果:

 

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

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

表达式i++的操做不走分解以下:

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

    2).计算i的值,

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

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

相关文章
相关标签/搜索