• synchronized 笔记


    1. 当一个线程正在访问一个对象的 synchronized 实例方法,那么其他线程不能访问该对象的其他 synchronized 方法

        对于每一个实例方法,锁是加在对象上的,一个线程访问其中一个 synchronized 修饰的实例方法时,这个线程就拿到了对象的锁,所以其他线程无法拿到该对象的锁,也就无法访问该对象的其他 synchronized 方法

    2. synchronized 修饰实例方法,两个(或多个)线程拿到同一个对象的锁,实现正确并发。

        一个简单的 +1 线程:

     1 class MyThread implements Runnable {
     2     static int i;
     3 
     4     public int getI() {
     5         return i;
     6     }
     7 
     8     public synchronized void incrI() {
     9         i++;
    10     }
    11 
    12     @Override
    13     public void run() {
    14         for (int j = 0; j < 1000000; j++) {
    15             incrI();
    16         }
    17     }
    18 }

        两个线程拿到同一个对象(myThread)的锁:

     1 public class SynTest {
     2     public static void main(String[] args) throws InterruptedException {
     3         MyThread myThread = new MyThread();
     4         Thread t1 = new Thread(myThread);
     5         Thread t2 = new Thread(myThread);
     6         t1.start();
     7         t2.start();
     8         t1.join();
     9         t2.join();
    10 
    11         System.out.println(MyThread.i);
    12     }
    13 }

    3. 当 synchronized 作用于静态方法时,其锁就是当前类的 class 对象锁。所以可以用两个不同的对象构造两个线程,但是这两个线程拿到的都是同一把锁(class 对象锁),所以仍然可以实现正确的并发。

    1 public synchronized static void incrI() {
    2     i++;
    3 }

       

     1 public class SynTest {
     2     public static void main(String[] args) throws InterruptedException {
     3         MyThread myThread = new MyThread();
     4         Thread t1 = new Thread(myThread);
     5         Thread t2 = new Thread(new MyThread());
     6         t1.start();
     7         t2.start();
     8         t1.join();
     9         t2.join();
    10 
    11         System.out.println(MyThread.i);
    12     }
    13 }

     4. synchronid 底层实现

        修饰代码块:monitorenter 和 monitorexit 指令。

        测试代码:

    1 public class SynBlock {
    2     private int i;
    3 
    4     public void incr() {
    5         synchronized (this) {
    6             i++;
    7         }
    8     }
    9 }

        javap 反编译之后:会有两个 exit,第一个是正常退出时执行,第二个是自动产生的,用于异常结束时执行

        

        修饰方法:使用 ACC_SYNCHRONIZED 标志

        

    5. synchronized 优化:偏向锁、轻量级锁

        偏向锁:同一个线程多次获取同一把锁时,无需申请,直接获取,有利于提高性能。适用于锁竞争不激烈的情况。

        轻量级锁:偏向锁失败之后,变为轻量级锁,适用于多个线程交替执行的情况,竞争少。

        自旋锁:会假设在不远的将来线程很快获得锁,让当前线程做空循环,如果可以获得锁,直接拿到,否则膨胀为重量级锁。

    6 . 可重入的含义:一个线程请求自己持有锁的资源,直接获取锁,无需再次申请。

    7. wait/notify/notifyAll 必须在 synchronized 中,因为这三个方法必须拿到 monitor 对象,而 synchronized 可以保证拿到 monitor 对象。

    参考:

    https://blog.csdn.net/javazejian/article/details/72828483

  • 相关阅读:
    vi 命令
    element-ui + el-dialog + Vue.component 注册的tinymce富文本控件 第二次及以后打开dialog出现问题解决方法
    【经典数据结构】哈希表
    TCP建立连接与释放连接过程中的几个问题
    【算法题目】求二叉树中节点的最大距离
    字符串处理函数
    [LeetCode] Balanced Binary Tree
    [LeetCode] N-Queens II
    [LeetCode] N-Queens
    【linux使用】bash shell命令行常用快捷键
  • 原文地址:https://www.cnblogs.com/ainsliaea/p/11370018.html
Copyright © 2020-2023  润新知