synchronized
三种应用方式
-
实例方法:锁是当前的实例对象
// 实例方法 多个线程访问对象的同一个方法 public class S1 implements Runnable{ static int a = 0; //共享 synchronized void add(){ a++; } @Override public void run() { for (int i = 0; i <2000 ; i++) { add(); } } public static void main(String[] args) throws InterruptedException { S1 s1 = new S1(); Thread t1 = new Thread(s1); Thread t2 = new Thread(s1); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(a); } } //输出:4000 //一个对象只有一把锁,多个线程同时对一个的对象的一个方法进行操作,只有一个线程能抢到锁,其他未抢到锁的线程不能访问该对象的其他synchronized实例方法 ,需要等待对象被释放后才能获取锁,对象没有被释放前,其他可以线程访问 非synchronized修饰的方法
-
静态方法
// 静态方法 public class S2 implements Runnable{ static int a = 0; //共享 static synchronized void add(){ a++; } @Override public void run() { for (int i = 0; i <2000 ; i++) { add(); } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new S2()); Thread t2 = new Thread(new S2()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(a); } } //输出:4000 //两个线程实例化不同的对象,但是访问的方法是static修饰的,两个线程发生了互斥,因为static方法依附于 类 ,不依赖于对象,当synchronized修饰static method时,锁是 class对象(唯一)
-
代码块
同步代码块 */ public class S3 implements Runnable{ static S3 syn = new S3(); //静态对象 static int a = 0; @Override public void run(){ //。。。 //。。。 // synchronized(syn){ //给定的实例对象 // for (int i = 0; i <2000 ; i++) { // a++; // } // } // synchronized(this){ //this对象(当前实例) // for (int i = 0; i <2000 ; i++) { // a++; // } // } synchronized(S3.class){ //calss对象 for (int i = 0; i <2000 ; i++) { a++; } } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(syn); Thread t2 = new Thread(syn); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(a); } }
volatile
定义:是Java虚拟机提供的轻量级同步机制。
特性
-
保证可见性
- 线程A和线程B共享同一变量,线程A对共享变量值修改后,线程B会得到最先的修改结果。
-
不保证原子性【可以使用 juc 下的atomic来保证原子性】
- 会因为线程调度器而被中断操作
-
禁止指令重排【通过 内存屏障 保证指令的有序性】
- 程序执行的最终结果与其顺序化执行的结果相同
- DCL中会造成线程不安全
指令重排: JVM允许指令执行的顺序与 代码逻辑书写的顺序可以不一致 意义: 指令更加符合CPU的特性,提高执行效率