关于多线程:多线程之线程可见性synchronized

39次阅读

共计 2059 个字符,预计需要花费 6 分钟才能阅读完成。

synchronized 的规定

  • 线程解锁前, 必须把共享变量刷新到主内存
  • 线程加锁前将清空工作内存共享变量的值, 须要从主存中获取共享变量的值。

加锁(synchronized 同步)的性能不仅仅局限于互斥行为,同时还存在另外一个重要的方面:内存可见性。咱们不仅心愿避免某个线程正在应用对象状态而另一个线程在同时批改该状态,而且还心愿确保当一个线程批改了对象状态后,其余线程可能看到该变动。而线程的同步恰好也可能实现这一点。

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

当线程 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

正文完
 0