Java--synchronized与Lock的区别和使用示例

1、Java锁的分类(参考链接:https://tech.meituan.com/2018/11/15/java-lock.html)

(1)乐观锁 VS 悲观锁:

​ 乐观锁:在获取数据时先加锁,确保数据不会被别的线程修改。synchronized关键字和Lock的实现类都是悲观锁。适合写操作频繁的场景。

​ 悲观锁:只在更新数据时判断有没有别的锁更新了这个数据,若有则通过报错或自动重试等执行操作,否则直接将自己修改的数据写入。适合读操作频繁的场景。

(2)公平锁 VS 非公平锁

​ 公平锁:多个线程按照申请锁的顺序来获取锁。

​ 非公平锁:多个线程加锁时直接尝试获取锁,若此时锁刚好可用,则该线程无需阻塞直接获取到锁,否则到等待队列的队尾等待。ReentrantLock(Lock的实现类)默认使用非公平锁,但可用通过构造器来指定使用公平锁。

(3)可重入锁 VS 非可重入锁

​ 可重入锁:举例说明,当一个线程执行某个synchronized方法时,比如method1(),且在method1()中会调用另一个synchronized方法method2(),此时线程不必重新申请锁而可用直接执行method2()(前提锁对象是同一个对象或者class)。示例代码如下:

class MyClass {
    public synchronized void method1() {
        method2();
    }

    public synchronized void method2() {

    }
}
(4)可中断锁 VS 非可中断锁

​ 可中断锁:在等待获取锁的过程中可中断,例如线程B在等待线程A释放锁,线程B由于等待时间太久可以主动中断等待锁。

(5)读写锁

​ 对资源的的读取和写入拆分为两部分处理,使用读锁保证多线程可以同步读取资源,使用写锁保证数据写入的同步。ReadWriteLock是一个读写锁,通过readLock()获取读锁,通过writeLock()获取写锁。

2、synchronized与Lock的区别

synchronizedLock
存在层次java的关键字,在jvm层面上一个接口
锁的获取假设A线程获取锁,B线程等待,若A线程阻塞,B线程会一直等待。可以尝试获取锁,若获取成功则线程不用一直等待(可以通过tryLock判断有没有锁)
锁的释放1、获取锁的线程执行完同步代码,释放锁;2、线程执行发生异常,jvm会让线程释放锁在finally中必须释放锁,不然容易造成线程死锁(一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被释放,以防死锁的发生)
锁的状态无法判断可以判断
锁的类型可重入、不可中断、非公平可重入、可中断、公平/非公平皆可

用法比较:

  • Lock必须手动获取和释放锁,而synchronized不需要手动释放和开启锁;
  • Lock只适用于代码块锁,而synchronizd可用于修饰方法、代码块等。

性能比较:

  • Lock可以提高多个线程进行读操作的效率(可以通过ReadWriteLock实现读写分离);
  • 在资源竞争不是很激烈的情况下,synchronize的性能由于ReetrantLock,但是在资源竞争很激烈的情况下,synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。

3、使用示例

(1)synchronized(参考链接:https://blog.csdn.net/luoweifu/article/details/46613015)
修饰静态方法
//同步线程
class SyncTHread implements Runnable{
    private static int number;

    public SyncTHread(){
        number=0;
    }

    public synchronized static void method(){
        for (int i=0;i<5;i++){
            try {
                System.out.println(Thread.currentThread().getName()+":"+(number++));
                Thread.sleep(100);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public synchronized void run(){
        method();
    }
}
//测试
public class testSynThread {
    public static void main(String[] args) {
        SyncTHread syncTHread1 = new SyncTHread();
        SyncTHread syncTHread2 = new SyncTHread();
        Thread thread1 = new Thread(syncTHread1, "SyncThread1");
        Thread thread2 = new Thread(syncTHread2, "SyncThread2");
        thread1.start();
        thread2.start();
    }
}
//运行结果
SyncThread10
SyncThread11
SyncThread12
SyncThread13
SyncThread14
SyncThread25
SyncThread26
SyncThread27
SyncThread28
SyncThread29

​ 在测试代码中,syncThread1和syncThread2是SyncThread的两个对象,但是在thread1和thread2并发执行时却保持了线程同步,因为run()中调用了静态方法method(),而synchronized修饰的静态方法锁定的是这个类的所有对象,所以syncThread1和syncThread2相当于使用了同一把锁。

(2)lock
class LockThread implements Runnable{
    private static int number;
    private ReentrantLock lock=new ReentrantLock();

    public LockThread(){
        number=0;
    }

    public void method(){
        try {
            lock.lock();
            for (int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+":"+(number++));
                Thread.sleep(100);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }


    public void run(){
        method();
    }
}

//测试
public class testLock{
    public static void main(String[] args) {
        LockThread lockThread1 = new LockThread();
        LockThread lockThread2 = new LockThread();
        Thread thread1 = new Thread(lockThread1, "lockThread1");
        Thread thread2 = new Thread(lockThread2, "lockThread2");
        thread1.start();
        thread2.start();
    }
}
//运行结果
lockThread1:0
lockThread2:1
lockThread1:2
lockThread2:2
lockThread2:3
lockThread1:4
lockThread1:5
lockThread2:5
lockThread2:6
lockThread1:7
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值