Thread - 多线程基本原理及分析

一 、synchronized关键字所修饰的范围之间的差别:

对象锁 | 类锁 : 是否跨对象、跨线程去保护

锁的大小: 无锁 < {偏向锁 < 轻量级锁 (无锁状态)} < 重量级锁 (真正意义上的锁)

什么是重量级锁: 重量级锁就是当一个线程占用了该锁的时候,另外线程访问了该锁时,该线程会被挂起,直到拿到锁的线程释放锁后才会唤醒挂起的线程

保证数据安全和性能的同时优化锁: 基于synchronized 锁的粒度控制

锁的升级过程:

1、偏向锁:当同步代码块只有一个线程访问 --> 引入偏向锁(记录当前线程的ThreadID,偏向锁标记),下一次该线程继续访问同步代码块的时候去比较当前线程的ThreadID是否和对象头中存储的时一致的。如果不一致,则表示有新的线程在抢占锁,该锁会自动升级为轻量级锁。

2、轻量级锁: 当线程A和线程B交替访问同步代码块时 --> 引入轻量级锁(自旋CAS获得锁 / 大部分线程在获得锁的时候,在非常短的时间内会释放锁 / 自旋方式比挂起线程更加节约资源 / 如果自旋指定次数之后还是没有获得锁,那么就所膨胀成重量级锁,阻塞线程)。 设置自旋次数: JVM参数 preBlockSpin 自适应自旋: JDK1.6之后提供

3、重量级锁: 当多个线程同时访问一个同步代码块的时候,锁自动升级为重量级锁,当拿到锁的线程还在执行同步代码块时,其他的线程会进入阻塞状态。
带synchronizd关键字的字节码,使用 javap -v *** .class 反编译为汇编指令。会发现有两个指令:moniterenter:监视器 / moniterexit:退出监视

重量级锁执行的逻辑:

 

1、修饰实例方法

所谓的修饰实例方法,指的是修饰当前被new 出来的对象

class Instance{
    //这是一把实例对象锁,如果不在同一个new关键字下产生的对象,则不会产生互斥作用
   public void synchronized instanceMethod(){
        
    }
}

public static void main(String[] args){
    Instance i = new Instance();
    i.instanceMethod();
    //这两者是不互斥的,因为synchronized作用在了实例对象上
    Instance ii = new Instance();
    ii.instanceMethod();
}

2、修饰静态方法

静态方法是属于类,如果将synchronied关键字方法静态方法上,则会出现不同实例上也会有互斥的效果

class Instance{
    //synchronized作用到static方法上
   public static void synchronized staticMethod(){
        
    }
}

public static void main(String[] args){
    Instance i = new Instance();
    i.staticMethod();
    //这两者锁是会产生相互互斥的效果。
    Instance ii = new Instance();
    ii.staticMethod();
}

3、修饰代码块: 减小了锁的粒度,性能更加高

修饰在代码块中会有两种情况:

1:代码块中锁的对象是 this 或者是 new Object()

class Instance{
    private Object lock = new Object();
    // 使用这样的锁,也是属于对象级别的
   public void method(){
       //TODO
        synchronized(lock / this){
            //保护共享变量的安全问题
        }
       //TODO
    }
}

public static void main(String[] args){
    Instance i = new Instance();
    i.instanceMethod();
    //不会产生互斥的效果
    Instance ii = new Instance();
    ii.instanceMethod();
}

2: 代码块中锁的对象为 Object.class

class Instance{
   public void method(){
     //TODO
     //class对象伴随着JVM类加载的时候加载,所以使用.class锁代码块,在不同实例不同线程也会被互斥的
        synchronized(Instance.class){
            //保护共享变量的安全问题
        }
       //TODO
    }
}

public static void main(String[] args){
    Instance i = new Instance();
    i.staticMethod();
    //这两者会产生互斥的效果,因为锁住了整个类
    Instance ii = new Instance();
    ii.staticMethod();
}

 

二 、对象在 JVM 中如何进行存储

32Hotspot虚拟机中, 使用 25bit + 4bit存储对象其他信息,1bit存储了是都是偏向锁,使用 2bit存储了锁的标志。

 

三、wait、notify、notifyAll

wait :实现线程的阻塞
notify/notifyAll : 实现线程的唤醒

public class ThreadA exdends Thread{
    //两个线程的锁对象必须是同一个锁对象
    private Object lock;
    
    public ThreadA(Object lock){
        this.lock = lock;
    }

    @Overried
    public void run(){
        synchronized(lock){
            System.out.println("strart TheadA");
            try{
                lock.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("end ThreadB");
        }
    }
}

public class ThreadB exdends Thread{
    //两个线程的锁对象必须是同一个锁对象
    private Object lock;
    
    public ThreadB(Object lock){
        this.lock = lock;
    }

    @Overried
    public void run(){
        synchronized(lock){			
            System.out.println("strart ThreadB");
            lock.notify();
			System.out.println("end ThreadB");
        }
    }
}

public class TestWaitNotify(){
    public static void main(String[] args){
        //两个线程的锁对象必须是同一个锁对象
        Object lock = new Object();
        new ThreadA(lock).strat();
        new ThreadB(lock).strat();
    }
}

//测试结果
strart ThreadA
strart ThreadB
end ThreadB
end ThreadA

由上诉测试结果标明,当 TheadA 进入了阻塞以后,开始执行 ThreadB, 当 ThreadB调用了notify()后, ThreadB执行完毕后,再执行了 ThreadA ,由此表明了当一个线程调用 wait() 后,会停止当前执行逻辑,并且会释放调持有的 lock 对象,当 ThreadB 持有 lock 对象后执行 notify() 通知ThreadA, 并且不会立即释放当前的 lock 对象,只有当 ThreadB 逻辑执行完毕后,才会释放 lock 对象,让 ThreadA继续执行。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值