多线程之线程可见性synchronized

synchronized的规定

  • 线程解锁前,必须把共享变量刷新到主内存
  • 线程加锁前将清空工做内存共享变量的值,须要从主存中获取共享变量的值。
加锁(synchronized 同步)的功能不单单局限于互斥行为,同时还存在另一个重要的方面:内存可见性。咱们不只但愿防止某个线程正在使用对象状态而另外一个线程在同时修改该状态,并且还但愿确保当一个线程修改了对象状态后,其余线程可以看到该变化。而线程的同步偏偏也可以实现这一点。

内置锁能够用于确保某个线程以一种可预测的方式来查看另外一个线程的执行结果。为了确保全部的线程都能看到共享变量的最新值,能够在全部执行读操做或写操做的线程上加上同一把锁。下图示例了同步的可见性保证。java

img

当线程 A 执行某个同步代码块时,线程 B 随后进入由同一个锁保护的同步代码块,这种状况下能够保证,当锁被释放前,A 看到的全部变量值(锁释放前,A 看到的变量包括 y 和 x)在 B 得到同一个锁后一样能够由 B 看到。换句话说,当线程 B 执行由锁保护的同步代码块时,能够看到线程 A 以前在同一个锁保护的同步代码块中的全部操做结果。若是在线程 A unlock M 以后,线程 B 才进入 lock M,那么线程 B 均可以看到线程 A unlock M 以前的操做,能够获得 i=1,j=1。若是在线程 B unlock M 以后,线程 A 才进入 lock M,那么线程 B 就不必定能看到线程 A 中的操做,所以 j 的值就不必定是 1。

synchronized线程可见性安全案例

package com.keytech.task;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class SynchronizedTestOne {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Rumenzz r=new Rumenzz();
        //线程1
        executorService.execute(()->{
              r.setAge(200);
        });
        //线程2
        executorService.execute(()->{
            System.out.println(r.getAge());
        });

        executorService.shutdown();
    }
}


class Rumenzz{
    private Integer age=0;

    public synchronized Integer getAge() {
        return age;
    }

    public synchronized void setAge(Integer age) {
        this.age = age;
    }
}
以上代码是线程安全的,输出 0200,由于线程1和线程2的执行顺序不同。为了保证结果的一致性,须要控制线程的执行顺序。
package com.keytech.task;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @className: SynchronizedTestOne
 * @description: TODO 类描述
 * @author: mac
 * @date: 2021/1/1
 **/
public class SynchronizedTestOne {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Rumenzz r=new Rumenzz();
        CountDownLatch c=new CountDownLatch(1);

        executorService.execute(()->{
            try {
                c.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(r.getAge());


        });
        executorService.execute(()->{
            try {
                Thread.sleep(5000);
                c.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r.setAge(200);
        });

        //关闭线程池
        executorService.shutdown();
    }
}


class Rumenzz{
    private Integer age=0;

    public synchronized Integer getAge() {
        return age;
    }

    public synchronized void setAge(Integer age) {
        this.age = age;
    }
}
线程安全输出 200

相关文章
相关标签/搜索