synchronized和lock的区别以及用法

1.synchronized锁是什么?

1):synchronized是Java的一个关键字,它能够将代码块(方法)锁起来
2):它是一个隐式锁,即:锁的持有与释放都是隐式的,我们无需干预
3):synchronized是非公平锁,它无法保证等待的线程获取锁的顺序
4):synchronized是一种互斥锁,一次只能允许一个线程进入被锁住的代码块
5):synchronized是一种内置锁/监视器锁,Java中每个对象都有一个内置锁(监视器,也可以理解成锁标记),而synchronized就是使用对象的内置锁(监视器)来将代码块(方法)锁定的

2.synchronized如何使用?

synchronized一般我们用来修饰三种东西:

修饰普通方法

修饰代码块

修饰静态方法

  • (1):修饰普通方法
public class TestSy {


    // 修饰普通方法,此时用的锁是TestSy对象(内置锁)
    public synchronized void test() {
       代码执行 ......
    }

}
  • (2):修饰代码块
public class TestSy {

    public  void test() {

        // 修饰代码块,此时用的锁是TestSy对象(内置锁)--->this
        synchronized (this){
            代码执行......
        }
    }
}
  • (3):修饰静态方法
public class TestSy {

    // 修饰静态方法代码块,静态方法属于类方法,它属于这个类,获取到的锁是属于类的锁(类的字节码文件对象)-->TestSy.class
    public synchronized void test() {
        代码执行.....
    }
}

3.lock锁是什么?

0):lock必须被显式地创建、锁定和释放,为了可以使用更多的功能,一般用ReentrantLock为其实例化。为了保证锁最终一定会被释放(可能会有异常发生),要把互斥区放在try语句块内,并在finally语句块中释放锁,尤其当有return语句时,return语句必须放在try字句中,以确保unlock()不会过早发生,从而将数据暴露给第二个任务。
1):与synchronized不同的是,它是显式锁,即锁的持有和释放都必须由我们手动编写
2):Lock对象锁还提供了synchronized所不具备的其他同步特性,如可中断锁的获取(synchronized在等待获取锁时是不可中的),超时中断锁的获取,等待唤醒机制的多条件变量Condition等

  • 使用样例如下:
     Lock lock = new ReentrantLock();//默认使用非公平锁,如果要使用公平锁,需要传入参数true
     ........
     lock.lock();
     try {
          //更新对象的状态
         //捕获异常,必要时恢复到原来的不变约束
        //如果有return语句,放在这里
    } finally {
            lock.unlock();        //锁必须在finally块中释放
    }

4.lock如何使用?

(1):lock主要接口和类如下:

synchronized和lock的区别以及用法_第1张图片
ReadWriteLock是读写锁接口,其实现类为ReetrantReadWriteLock。ReetrantLock实现了Lock接口。

(2):lock的主要方法

synchronized和lock的区别以及用法_第2张图片

  • lock:用来获取锁,如果锁被其他线程获取,处于等待状态。如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

  • lockInterruptibly:通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。

  • tryLock:tryLock方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。

  • tryLock(long,TimeUnit):与tryLock类似,只不过是有等待时间,在等待时间内获取到锁返回true,超时返回false。

  • unlock:释放锁,一定要在finally块中释放

(3):ReetrantLock

ReentrantLock和synchronized关键字一样可以用来实现线程之间的同步互斥,但是在功能是比synchronized关键字更强大而且更灵活。

(4):ReadWriteLock
public interface ReadWriteLock {  
    Lock readLock();       //获取读锁  
    Lock writeLock();      //获取写锁  
}  

一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。ReentrantReadWirteLock实现了ReadWirteLock接口,并未实现Lock接口。

不过要注意的是:
如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。

如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。

(5):ReetrantReadWriteLock

ReetrantReadWriteLock同样支持公平性选择,支持重进入,锁降级。

public class testLock {
    static Map<String, Object> map = new HashMap<String, Object>();
    static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    static Lock r = rwLock.readLock();
    static Lock w = rwLock.writeLock();
    //读
    public static final Object get(String key){
        r.lock();
        try {
            return map.get(key);
        } finally {
            r.unlock();
        }
    }
    //写
    public static final Object put(String key, Object value){
        w.lock();
        try {
            return map.put(key, value);
        } finally {
            w.unlock();
        }
    }
}

只需在读操作时获取读锁,写操作时获取写锁。当写锁被获取时,后续的读写操作都会被阻塞,写锁释放后,所有操作继续执行。

5.区别总结

网上的说法也是很多,小刘自己也浏览资料,梳理了一些。如下:

  • 1.Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

  • 2.synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

  • 3.Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

  • 4.通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

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

  • 6.性能上来说,在资源竞争不激烈的情形下,Lock性能稍微比synchronized差点(编译程序通常会尽可能的进行优化synchronized)。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

  • 7.synchronized不如lock灵活。Lock和synchronize都是默认使用非公平锁的。如果不是必要的情况下,不要使用公平锁

  • 8.总的来说,一般只要不是需要lock的灵活性,还是推荐使用synchronized,毕竟synchronized 在JDK1.6后,被优化加强了很多。

参考资料:
https://juejin.im/post/6844903542440869896#heading-5

你可能感兴趣的:(Java,并发编程,面试)