在jdk1.6之前,Synchronized是基于重量级锁实现的,就是说,当多个线程竞争同一把锁的时候,
如果获取不到锁,线程就会阻塞,等待锁的释放,直到获取锁。

Synchronized是jvm层面的锁。无锁->偏向锁->轻量级锁->重量级锁的升级是jvm实现的。锁升级后是不能降级的。

偏向锁,轻量级锁 是无锁化实现的,是乐观锁。重量级锁是悲观锁。

偏向锁是通过cas方式实现的。

轻量级锁是采用自旋(为什么用自旋,而不用挂起?因为大部分情况下,某个线程获取锁以后会很快释放锁,这个时候如果让线程挂起会消耗性能,所以使用自旋的方式获取锁性能更好。但是自旋后浪费cpu自旋,所以在自旋一定次数以后如果还没有获取到锁,就会进行挂起,膨胀为重量级锁。自旋次数有自己设置和自适应,通过preBlockSpin参数进行设置)的方式实现的。

之后,Synchronized优化为偏向锁,轻量级锁,重量级锁按条件处理的方式。

假如有2个线程ThreadA、和ThreadB:
    1.大部分情况下,只有ThreadA去访问,这个时候对象头存放的是轻量级锁标记,记录的是ThreadA线程的线程id以及偏向锁标记
    2.当ThreadA和ThreadB交替访问的时候,会转化为轻量级锁,通过自旋的方式获取锁。
    3.当多个线程同时访问的时候,由于通过轻量级锁也无法获取锁,就会转化为重量级锁,对获取不到锁的线程进行阻塞挂起。

 

 

redision 自旋锁_同步锁

redision 自旋锁_System_02

redision 自旋锁_java_03

redision 自旋锁_System_04

 

package com.example;

public class ThreadA extends Thread {
    Object lock ;
    public ThreadA(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        System.out.println("start thread A");
        synchronized (lock){
            try {
                lock.wait();//阻塞并且释放锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("end thread A");
    }
}
package com.example;

public class ThreadB extends Thread {
    Object lock ;
    public ThreadB(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        System.out.println("start thread B");
        synchronized (lock){
            try {
                lock.notify();//唤醒其他阻塞的线程
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("end thread B");
    }
}
package com.example;

public class WaitNotifyTest {
    public static void main(String[] args) {
        Object lock = new Object();
        //wait 1.实现线程的阻塞,2.释放当前的同步锁
        ThreadA threadA = new ThreadA(lock);
        threadA.start();
        //notify 1.唤醒被阻塞的线程
        ThreadB threadB = new ThreadB(lock);
        threadB.start();

    }
}

输出结果:

start thread A    线程a启动,获得同步锁,启动后wait() ,线程阻塞,释放锁  ,a会被放到线程“等待队列”中。
start thread B    线程b启动,唤醒其他阻塞的线程a,a会被放到"同步队列中",等待争取锁,此时锁掌握在b手中,a无法获取锁,只能等b释放锁以后a才能获取锁执行。线程b只能唤醒等待同一把锁的线:a等待lock锁
end thread B     线程b执行结束,释放锁。
end thread A     线程a获取锁,继续执行。

redision 自旋锁_java_05

 

线程wait后进入等待队列,等待被唤醒,其他线程notify唤醒后进入同步队列,等待争抢锁