Synchronized与Lock

1、线程安全问题

多线程访问一个共享资源时,可能会致使运行结果不是预计的结果。数据库

好比两个线程要往数据库中插入一条数据。安全

两个线程先检查数据库中有没有这个数据,都检测到没有,因而都插入一条数据。但实际上只须要一条数据。多线程

对共享资源操做时,才会有线程安全问题。线程

2、解决方法

序列化访问临界资源。同一时刻,只有一个线程访问临界资源。也叫同步互斥访问。code

synchronized和Lock对象

3、synchronized

做用是给共享资源加上互斥锁。当一个线程访问时,其余线程等待访问。接口

synchronized能够锁方法,也能够锁代码块。资源

synchronized的本质是锁对象。同步

Java中,每个对象都有一个所标记monitor。多线程访问某个对象时,线程只有得到了该对象的锁,才能访问。源码

三种情形

1.一个线程访问一个对象的synchronized方法时,另外一个线程不能访问该对象的synchronized方法,可是能够访问非synchronized方法。

2.一个线程访问一个对象object1的synchronized方法时,另外一个线程能够访问对象object2的synchronized方法。object1和object2是同一个类型。 由于访问的对象不同。

3.一个线程访问一个对象的非静态synchronized方法时,另外一个线程能够访问该对象的静态synchronized方法。

由于静态synchronized方法,占领的锁是类锁,不是对象锁。

汇编指令

synchronized编译成两条指令:monitorenter和monitorexit

monitorenter会让对象的锁计数加1。 monitorexist会让对象的锁计数减1。

抛出异常时,会释放锁对象,不会出现死锁。

4、Lock

synchronized的缺陷

synchronized释放锁有两种状况:1.线程执行完,2.出现中断异常。

若是synchronized中线程阻塞,其余线程就要一直等待,很是影响效率。

因而就提供了功能更强大的Lock,来解决一些问题

Lock源码

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

synchronized是Java的内置关键字。Lock是一个接口。

Lock中有这么几个方法:

lock(),unLock()

lock()用来获取锁,若是其余线程已经获取了锁,那么就等待。

和synchronized不同。Lock不会自动释放锁。因此必须手动释放锁,用unLock()。 通常放在try...catch()...finally()中。

tryLock()

tryLock有返回值,尝试获取锁,若是获取了锁,就返回true,没有获取锁,就返回false。也就是说,这个方法不会等待锁。

通常用if(tryLock())..else...

lockInterruptibly()

使用lockInterruptibly()获取锁的状况下,若是线程处于等待获取锁的状态,调用interrupt能够中断线程,抛出异常。

ReentrantLock

实现了Lock的类。能够实现可重入锁。

ReadWriteLock和ReentrantReadWriteLock

是一个接口。定义了两个方法。ReentrantReadWriteLock实现了该接口。

readLock()和writeLock()分别获取读锁和写锁。

一个线程获取了读锁,另外一个线程能够得到该对象的读锁,不能得到该对象的写锁。

一个线程获取了写锁,另外一个线程不能够获取该对象的读写锁。

支持降级,写锁能够降级为读锁,可是读锁不能升级为写锁。

5、Lock和Synchronized的选择

1.synchronized是Java内置关键字,Lock是接口。

2.synchronized异常会自动释放锁,Lock要手动释放。

3.synchronized没法中断等待获取锁的线程,Lock能够。

4.synchronized没法判断线程是否获取锁,Lock能够。

5.Lock可使用读锁,提升读线程的效率。

6、锁的类型

可重入锁

一个锁方法中调用另外一个锁方法,线程不须要从新获取锁对象。

synchronized和Lock都是可重入锁

公平锁

等待获取锁的线程按请求顺序获取锁对象。

synchronized是非公平锁。 Lock默认是非公平锁。可是能够设置为公平锁。

ReentrantLock lock = new ReentrantLock(true);

可中断锁

能够中断等待锁的线程。

synchronized是不可中断锁。Lock是可中断锁。

读写锁

锁分红两个,一个读锁,一个写锁。

synchronized没有,ReadWriteLock是读写锁。

相关文章
相关标签/搜索