synchronized和Lock锁的区别

synchronized

java中每一个对象都可以作为一把锁,而这把锁就是synchronized关键字存在的理由:
1.synchronized修饰静态方法,代表的锁的是这个类对象.

public synchronized static void test(){}

2.synchronized修饰普通方法,代表锁的是当前实例对象

public synchronized void test(){}

3.在同步代码块中也分为实例对象锁和类锁

public class Test{
public void test(){
synchronized(Test.class){//类锁
}
}
public void test1(){
synchronized(this)//实例对象锁
}

当一个线程访问同步代码块时,它首先是需要得到锁,当退出或者抛出异常时必须要释放锁,那么它是如何来实现这个机制的呢?我们先看一段简单的代码:

public class synchronizedTest {
    public synchronized void test(){}
    public void test1(){
        synchronized (synchronizedTest.class){
        }
    }

    public static void main(String[] args) {

    }
}

在这里插入图片描述
在这里插入图片描述
可以看出同步代码块是通过monitorenter和monitorexit两个成对的指令来完成的,下面来看看修饰方法的原理.

public synchronized void foo() {
System.out.println("hello world");
}

public synchronized void foo();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED // 看这里
Code:
stack=2, locals=1, args_size=1
0: getstatic #5 // Field
java/lang/System.out:Ljava/io/PrintStream;
3: ldc #6 // String hello world
5: invokevirtual #7 // Method
java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 9: 0
line 10: 8
}
同步代码块

monitorenter指令编译后插入到同步代码块开始的位置,monitorexit指令在编译后会插入到同步代码块结束的位置.JVM需要保证每一个monitorenter都有一个monitorexit与之相对应。任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁;

同步方法

当用 synchronized 标记方法时,你会看到字节码中方法的访问标记包括 ACC_SYNCHRONIZED。该标记表示在进入该方法时,Java 虚拟机需要进行 monitorenter 操作。而在退出该方法时,不管是正常返回,还是向调用者抛异常,Java 虚拟机均需要进行 monitorexit 操作。
这里 monitorenter 和 monitorexit 操作所对应的锁对象是隐式的。对于实例例方法来说,这两个操作对
应的锁对象是 this;对于静态方法来说,这两个操作对应的锁对象则是所在类的 Class 实例。
synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令,在jVM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法,而是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位置1,表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象做为锁对象。

Lock

lock锁机制也是一种解决线程安全的一种方法,他其实是程序员写出来的一种东西,所以由此可知Lock就是用来解决线程安全的一个接口.

synchronized和 Lock对比

在jdk1.5之前synchronized关键字的性能是远远不及lock的,但在jdk1.6之后对synchronized进行了锁粗化,锁消除,自适应自旋偏向锁一系列优化,其性能得到了大大的改善,不lock锁机制不相上下.
在这里插入图片描述
区别:
1.来源:
lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;

2.异常是否释放锁:
synchronized在发生异常时候会自动释放占有的锁,因此不会出现死锁;而lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生。(所以最好将同步代码块用try catch包起来,finally中写入unlock,避免死锁的发生。)

3.是否响应中断
lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断;

4.是否知道获取锁
Lock可以通过trylock来知道有没有获取锁,而synchronized不能;

5.Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)

6.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

7.synchronized使用Object对象本身的wait 、notify、notifyAll调度机制,而Lock可以使用Condition进行线程之间的调度,

8.synchronized是悲观锁,lock是乐观锁

用途区别:

synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。

1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值