内置锁(一)synchronized 介绍与用法

一、synchronized 的介绍

  synchronized 是 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,而这段代码也被称为临界区。

  synchronized 有多个叫法,而每个叫法都表明synchronized 的特性:

1、内置锁(又叫 隐式锁):synchronized 是内置于JDK中的,底层实现是native;同时,加锁、解锁都是JDK自动完成,不需要用户显式地控制,非常方便。

2、同步锁:synchronized 用于同步线程,使线程互斥地访问某段代码块、方法。这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

3、对象锁:准确来说,是分为对象锁、类锁。synchronized 以当前的某个对象为锁,线程必须通过互斥竞争拿到这把对象锁,从而才能访问 临界区的代码,访问结束后,就会释放锁,下一个线程才有可能获取锁来访问临界区(被锁住的代码区域)。synchronized锁 根据锁的范围分为 对象锁 和 类锁。对象锁,是以对象实例为锁,当多个线程共享访问这个对象实例下的临界区,只需要竞争这个对象实例便可,不同对象实例下的临界区是不用互斥访问;而类锁,则是以类的class对象为锁,这个锁下的临界区,所有线程都必须互斥访问,尽管是使用了不同的对象实例;

总的来说对象锁的粒度要比类锁的粒度要细,引起线程竞争锁的情况比类锁要少的多,所以尽量别用类锁,锁的粒度越少越好。
看下面的例子:

<span style="color:#000000"><code>    FruitCount fruitCount = <span style="color:#0000ff">new</span> FruitCount();
    FruitCount fruitCount_3 = <span style="color:#0000ff">new</span> FruitCount();
    <span style="color:#008000">//线程1、2 使用了同一个FruitCount对象(fruitCount )</span>
    Thread thread_1 = <span style="color:#0000ff">new</span> Thread(<span style="color:#0000ff">new</span> MyRunable(fruitCount));
    Thread thread_2 = <span style="color:#0000ff">new</span> Thread(<span style="color:#0000ff">new</span> MyRunable(fruitCount));
    <span style="color:#008000">//线程3使用了不同的FruitCount对象(fruitCount_3 )</span>
    Thread thread_3 = <span style="color:#0000ff">new</span> Thread(<span style="color:#0000ff">new</span> MyRunable(fruitCount_3));</code></span>

   线程1、2将会互斥访问getAmount( )方法,线程3则独享getAmount( )方法;线程1、2的getAmount( )方法中的对象锁是fruitCount ,线程3的则是 fruitCount_3;这便是对象锁的粒度范围,不同的对象,锁是相互隔离的。而对于setData( )方法,三个线程都要互斥访问访问它,因为是同一个锁 -- FruitCount.class类锁。

<span style="color:#000000"><code><span style="color:#0000ff">class</span> <span style="color:#a31515">FruitCount</span>{
    
   <span style="color:#0000ff">static</span> <span style="color:#0000ff">int</span> price = 5;
   <span style="color:#0000ff">static</span> <span style="color:#0000ff">int</span> num = 10;
    
    <span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">setData</span>(<span style="color:#0000ff">int</span> price,<span style="color:#0000ff">int</span> num){
        <span style="color:#008000">//类锁,以FruitCount.class为锁</span>
        <span style="color:#0000ff">synchronized</span>(FruitCount.class){
            <span style="color:#0000ff">this</span>.price = price;
            <span style="color:#0000ff">this</span>.num = num;
        }
    }
    
    <span style="color:#0000ff">public</span> <span style="color:#0000ff">int</span> <span style="color:#a31515">getAmount</span>(){
        <span style="color:#008000">//对象锁,以当前对象为锁</span>
        <span style="color:#0000ff">synchronized</span> (<span style="color:#0000ff">this</span>) {
            <span style="color:#0000ff">int</span> amount = price*num;
            <span style="color:#0000ff">return</span> amount;
        }
    }
}</code></span>
class MyRunable implements Runnable{
 
    FruitCount fruitCount;
    public MyRunable(FruitCount fruitCount){
        this.fruitCount = fruitCount;
    }
    
    @Override
    public void run() {
        //setData方法 有类锁
        fruitCount.setData(5, 10);
        //getAmount方法 里面有对象锁,就是fruitCount对象
        fruitCount.getAmount();
    }   
}

二、synchronized 用法

synchronized 的用法只有两种:修饰方法修饰代码块

1、在方法声明时使用,修饰方法

注意:这个synchronized 修饰符 不会参与方法签名的比较;

语法:

<span style="color:#000000"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">synchronized</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">synMethod</span>() {
               <span style="color:#008000">//方法体</span>
   }</code></span>

有以下两种情况:

  • 1.1、修饰的方法是普通的成员方法,那么是对象锁,便是以当前对象为锁,即调用这个方法的对象
  • 1.2、修饰的方法是静态方法,则是类锁
<span style="color:#000000"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">synchronized</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">int</span> <span style="color:#a31515">countData</span>(<span style="color:#0000ff">int</span> data){
      <span style="color:#0000ff">return</span> data*data;
}</code></span>

2、修饰一个代码块

语法:

<span style="color:#000000"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">int</span> <span style="color:#a31515">synMethod</span>(<span style="color:#0000ff">int</span> a1){
    <span style="color:#0000ff">synchronized</span>( object ) {
            <span style="color:#008000">//代码块,一次只能有一个线程进入</span>
    }
   }</code></span>

有以下3种情况:

2.1、object 是 this,是对象锁,this指代当前对象

<span style="color:#000000"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">int</span> <span style="color:#a31515">getAmount</span>(){
        <span style="color:#008000">//对象锁,以当前对象为锁</span>
        <span style="color:#0000ff">synchronized</span> (<span style="color:#0000ff">this</span>) {
            <span style="color:#0000ff">int</span> amount = price*num;
            <span style="color:#0000ff">return</span> amount;
        }
    }</code></span>

2.2、object 是一个普通对象实例

  • 如果是静态对象,那么就是 类锁
  • 如果是非静态对象:成员对象变量、局部变量(甚至可以是 方法参数),那么就是对象锁
<span style="color:#000000"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">setObj</span>(){
        FruitCount fruitCount = <span style="color:#0000ff">null</span>;
        <span style="color:#008000">//局部变量</span>
        <span style="color:#0000ff">synchronized</span>(fruitCount){
            fruitCount = <span style="color:#0000ff">new</span> FruitCount();
        }
    }</code></span>

2.3、object 是一个类的class 对象,那么就是类锁

<span style="color:#000000"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">setData</span>(<span style="color:#0000ff">int</span> price,<span style="color:#0000ff">int</span> num){
        <span style="color:#008000">//类锁,以FruitCount.class为锁</span>
        <span style="color:#0000ff">synchronized</span>(FruitCount.class){
            <span style="color:#0000ff">this</span>.price = price;
            <span style="color:#0000ff">this</span>.num = num;
        }
    }</code></span>

小 结:

1、出现类锁的情况:

  • 以 类.class 为锁
  • 以 静态变量为锁
  • 修饰静态方法

2、出现对象锁的情况:

  • 以实例成员对象为锁(特殊:this 指当前对象)
  • 以局部变量(甚至是方法传进来的参数)为锁、
  • 修饰成员方法

3、当synchronized修饰方法时,synchronized是不参与 方法签名的比较;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值