synchronized 笔记

时间:2019-08-18
本文章向大家介绍synchronized 笔记,主要包括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

原文地址:https://www.cnblogs.com/ainsliaea/p/11370018.html