打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Synchronized简介与原理

一、作用

1. 多线程同步代码,保证方法或者代码块在运行时,同一时刻只有一个线程可以进入到临界区(互斥性)

2. 保证线程间共享变量的修改及时可见(可见性)

a. 当线程获取锁时,线程的本地变量无效,需要从主存中获取共享变量的值

b. 线程释放锁时,线程的本地变量被刷新到主存中

3. 有效解决重排序问题(有序性)

二、用法

1. Java中的每个对象都可以作为锁,获取的锁都是对象

2. 修饰函数,即普通同步方法,锁是当前类的实例对象 public void synchronized A(){}

3. 静态同步方法,锁是当前类的class对象 public static void synchronized A(){}

4. 修饰函数内的语句块,即同步代码块,锁是括号中的对象 synchronized(obj){}

5. 每个对象只有一个锁(lock)与之关联

6. 作用域

a. 某个对象实例内的方法,不同对象的实例内的方法不相干扰,其他线程可以同时访问相同类的其他对象实例中的synchronized方法

b. 某个类的范围,一般是静态方法,可以防止多个线程同时访问相同类中的synchronized方法

三、原理

1. java示例代码,同步静态方法

public class SynchronizedTest {    private static Object object = new Object();    public static void main(String[] args) throws Exception{        synchronized(object) {                    }    }    public static synchronized void m() {}}

2. 代码->字节码->反编译后的代码

public static void main(java.lang.String[]) throws java.lang.Exception;    descriptor: ([Ljava/lang/String;)V    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=2, locals=3, args_size=1         0: getstatic     #2                  // Field object:Ljava/lang/Object         3: dup         4: astore_1         5: monitorenter            //监视器进入,获取锁         6: aload_1         7: monitorexit              //监视器退出,释放锁         8: goto          16        11: astore_2        12: aload_1        13: monitorexit        14: aload_2        15: athrow        16: return        public static synchronized void m();   descriptor: ()V   flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED   Code:     stack=0, locals=0, args_size=0        0: return     LineNumberTable:       line 9: 0

3. 同步代码块使用monitorenter和monitorexit指令实现

4. 同步方法使用修饰符ACC_SYNCHRONIZED实现

5. 无论哪种实现,本质上都是对monitor的获取,这个过程是互斥的

四、锁的状态

1. 对象头:

a. 对象在内存中分为3部分:对象头、实例数据、对齐填充

b. 对象头可以记录对象的状态:偏向锁、轻量级锁、重量级锁

2. monitor:

a. 线程私有的数据结构,每个线程有一个monitor列表

b. JVM记录获取monitor锁的线程唯一id,确保一次只有一个线程执行

3. 偏向锁状态:

a. 如果一个线程获取了锁,那么锁就进入了偏向状态

b. 当这个线程再次请求锁时,不需要再做同步,就可以获取锁,避免了申请锁的操作,优化了性能

c. 适用于没有激烈竞争锁的情况,不仅没有多线程竞争,而且总是由同一个线程获取锁

4. 轻量级锁状态:

a. 获取偏向锁失败后,会膨胀为轻量级锁

b. 适用于交替执行同步块的情况

5. 重量级锁状态:

a. 获取轻量级锁失败后,会膨胀为重量级锁

b. 此时所有线程都会被锁住,当前获取锁的线程释放后,其他线程才被唤醒

五、等待通知机制,即wait(),notify(),notifyall()进行线程间通信

1. 代码

public class WaitNotify {    static boolean flag = true;    static Object lock = new Object();    public static void main(String[] args) throws InterruptedException {        Thread A = new Thread(new Wait(), "wait thread");        A.start();        TimeUnit.SECONDS.sleep(2);        Thread B = new Thread(new Notify(), "notify thread");        B.start();    }    static class Wait implements Runnable {        @Override        public void run() {            synchronized (lock) {                while (flag) {                    try {                        System.out.println(Thread.currentThread()   " flag is true");                        lock.wait();                    } catch (InterruptedException e) {                    }                }                System.out.println(Thread.currentThread()   " flag is false");            }        }    }    static class Notify implements Runnable {        @Override        public void run() {            synchronized (lock) {                flag = false;                lock.notifyAll();                try {                    TimeUnit.SECONDS.sleep(7);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

2. 使用wait(),notify(),notifyAll()时,需要先对对象加锁

3. 调用wait()方法后,线程会释放锁,线程状态RUNNING->WAITING,将线程移动到等待队列

4. notify()/notifyAll()时,等待线程不会立即从wait()返回,需要当前线程释放锁之后,才有机会获取锁返回

5. notify()将一个等待队列里的线程,移动到同步队列,线程状态WAITING->BLOCKED

6. notifyAll()将所有等待队列里的线程,移动到同步队列,线程状态WAITING->BLOCKED

7. 线程只有获取了锁,才能从wait()返回

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
java线程概述 -- JR 精品文章
关于Java多线程实现生产者和消费者的问题
Java并发编程之内置锁(synchronized)
如何解决多线程带来的线程安全问题
写两个线程,一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z
Android:线程的结束,挂起和恢复(下)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服