您当前的位置: 首页 >  Java
  • 0浏览

    0关注

    1477博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

java并发编程(1)--线程 可见性 volatile怎么用

软件工程小施同学 发布时间:2021-02-06 12:02:49 ,浏览量:0

一、每个Java线程都有⾃⼰的⼯作内存

操作数据,⾸先从主内存中读,得到⼀份拷⻉,操作完毕后再写回到主内存。

不同的线程间⽆法访问对⽅的⼯作内存,线程间的通信 (传值)必须通过主内存来完成

 

二、不同的线程间⽆法访问对⽅的⼯作内存
package thread;

import java.util.concurrent.TimeUnit;

/**
 * volitale关键字是Java提供的⼀种轻量级同步机制。
 * 它能够保证可⻅性和有序性
 * 但是不能保证原⼦性
 * 禁⽌指令重排
 */
class MyData {

    int number = 0;
    // volatile int number = 0;

    public void setTo60() {
        this.number = 60;
    }

}

public class VolatileDemo {

    public static void main(String[] args) {
        volatileVisibilityDemo();
    }

    // volatile可以保证可⻅性,及时通知其它线程主物理内存的值已被修改
    private static void volatileVisibilityDemo() {

        System.out.println("可⻅性测试");
        MyData myData = new MyData();//资源类

        // 启动⼀个线程操作共享数据
        new Thread(() -> {

            System.out.println(Thread.currentThread().getName() + "\t 执⾏");

            try {

                TimeUnit.SECONDS.sleep(3);

                // 更新number的值
                myData.setTo60();

                System.out.println(Thread.currentThread().getName() + "\t 更新number值: " + myData.number);

            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }

        }, "ThreadA").start();


        // main线程,获取共享变量改变后的结果
        while (myData.number == 0) {
            // main线程持有共享数据的拷⻉,⼀直为0
            // 若number的值一直为0,说明main线程没有得到共享变量改变值的通知

        }

        System.out.println(Thread.currentThread().getName() + "\t main获取 number值: " + myData.number);

    }
}

虽然⼀个线程把number修改成了60,但是main线程持有的仍然是最开始的0,所以⼀直循环,程序不会结束。

 

三、如果对变量添加了volatile修饰
package thread;

import java.util.concurrent.TimeUnit;

/**
 * volitale关键字是Java提供的⼀种轻量级同步机制。
 * 它能够保证可⻅性和有序性
 * 但是不能保证原⼦性
 * 禁⽌指令重排
 */
class MyData {

    // int number = 0;
    volatile int number = 0;

    public void setTo60() {
        this.number = 60;
    }

}

public class VolatileDemo {

    public static void main(String[] args) {
        volatileVisibilityDemo();
    }

    // volatile可以保证可⻅性,及时通知其它线程主物理内存的值已被修改
    private static void volatileVisibilityDemo() {

        System.out.println("可⻅性测试");
        MyData myData = new MyData();//资源类

        // 启动⼀个线程操作共享数据
        new Thread(() -> {

            System.out.println(Thread.currentThread().getName() + "\t 执⾏");

            try {

                TimeUnit.SECONDS.sleep(3);

                // 更新number的值
                myData.setTo60();

                System.out.println(Thread.currentThread().getName() + "\t 更新number值: " + myData.number);

            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }

        }, "ThreadA").start();


        // main线程,获取共享变量改变后的结果
        while (myData.number == 0) {
            // main线程持有共享数据的拷⻉,⼀直为0
            // 若number的值一直为0,说明main线程没有得到共享变量改变值的通知
            // System.out.println(Thread.currentThread().getName() + "\t 等待。。。 ");
        }

        System.out.println(Thread.currentThread().getName() + "\t main获取 number值: " + myData.number);

    }
}

可⻅某个线程对number的修改,会⽴刻反映到主内存上。

每个线程是独立的,但是线程对变量的所有操作都必须在拷贝到自己的工作内存中进行,而不能直接读写主内存中的变量。

不同线程之间也无法直接访问对方工作内存中的变量。

当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去主内存中读取新值,所以可见性是立即可见的意思。

如果没有加volatile,线程A修改了,还没来得及写回主内存,另一个线程也要修改,但是他没保证可见性,去主内存没拿到线程A修改的最新的值,就会出现问题。

 

 

四、System.out.println()有锁

即使没有volitale修饰

package thread;

import java.util.concurrent.TimeUnit;

/**
 * volitale关键字是Java提供的⼀种轻量级同步机制。
 * 它能够保证可⻅性和有序性
 * 但是不能保证原⼦性
 * 禁⽌指令重排
 */
class MyData {

    int number = 0;
    // volatile int number = 0;

    public void setTo60() {
        this.number = 60;
    }

}

public class VolatileDemo {

    public static void main(String[] args) {
        volatileVisibilityDemo();
    }

    // volatile可以保证可⻅性,及时通知其它线程主物理内存的值已被修改
    private static void volatileVisibilityDemo() {

        System.out.println("可⻅性测试");
        MyData myData = new MyData();//资源类

        // 启动⼀个线程操作共享数据
        new Thread(() -> {

            System.out.println(Thread.currentThread().getName() + "\t 执⾏");

            try {

                TimeUnit.SECONDS.sleep(3);

                // 更新number的值
                myData.setTo60();

                System.out.println(Thread.currentThread().getName() + "\t 更新number值: " + myData.number);

            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }

        }, "ThreadA").start();


        // main线程,获取共享变量改变后的结果
        while (myData.number == 0) {
            // main线程持有共享数据的拷⻉,⼀直为0
            // 若number的值一直为0,说明main线程没有得到共享变量改变值的通知
            System.out.println(Thread.currentThread().getName() + "\t 等待。。。 ");
        }

        System.out.println(Thread.currentThread().getName() + "\t main获取 number值: " + myData.number);

    }
}

结果

原因 synchronized

 

 

 

 

 

 

 

 

 

 

 

 

关注
打赏
1665320866
查看更多评论
立即登录/注册

微信扫码登录

0.0417s