当对数据修改时,若是两个线程同时去修改同一条数据,这样产生的结果就不是咱们预期的结果。这时候就须要对修改操做进行加锁,让jvm里同一时刻只能有一个线程可以执行修改方法。java
下面是一个未加锁的修改方法: 多线程
public void update(Entry entry){ dao.update(entry); }
如今讨论下传统的加锁方法。咱们知道每个对象都隐含了一个锁,那就是对象自己。咱们能够在方法体上加上同步字段synchronizedjvm
public synchronized void update(Entry entry){ dao.update(entry); }
但若是方法里代码不少,那么加在方法上会锁住不少代码,咱们可使用同步块性能
public void update(Entry entry){ dobefore(); synchronized(this){ dao.update(entry); } doend(); }
而须要注意的是若是一个类中存在多个同步方法,那么全部同步方法的锁都是对象自己,也就是说当执行update的时候,别的线程不只不能执行update连类中别的同步方法也不能使用。固然也可使用一点技巧去规避这个问题,好比使用其余锁。this
咱们这篇博客说得不是上面的方法,而是另一个位于java.util.concurrent.locks包下的ReentrantLock。spa
官方是这么说的:线程
一个可重入的互斥锁 Lock,它具备与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
ReentrantLock 将由最近成功得到锁,而且尚未释放该锁的线程所拥有。当锁没有被另外一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。若是当前线程已经拥有该锁,此方法将当即返回。可使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此状况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。不然此锁将没法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的整体吞吐量(即速度很慢,经常极其慢),可是在得到锁和保证锁分配的均衡性时差别较小。不过要注意的是,公平锁不能保证线程调度的公平性。所以,使用公平锁的众多线程中的一员可能得到多倍的成功机会,这种状况发生在其余活动线程没有被处理而且目前并未持有锁时。还要注意的是,未定时的 tryLock 方法并无使用公平设置。由于即便其余线程正在等待,只要该锁是可用的,此方法就能够得到成功。code
使用它也很简单,你能够用以下结构来使用他: 对象
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
经常使用的方法就如上面所说的同样,lock和unlock 接口
lock public void lock() 获取锁。 若是该锁没有被另外一个线程保持,则获取该锁并当即返回,将锁的保持计数设置为 1。 若是当前线程已经保持该锁,则将保持计数加 1,而且该方法当即返回。 若是该锁被另外一个线程保持,则出于线程调度的目的,禁用当前线程,而且在得到锁以前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。 指定者: 接口 Lock 中的 lock unlock public void unlock() 试图释放此锁。 若是当前线程是此锁全部者,则将保持计数减 1。若是保持计数如今为 0,则释放该锁。若是当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException。 指定者: 接口 Lock 中的 unlock 抛出: IllegalMonitorStateException - 若是当前线程没有保持此锁
固然他还有别的不少方法,须要的话能够本身去看看。
对比synchronized这个锁是独立的,在一个类中多个同步块之间都是独立的,互不影响。最后说一句,由于同步块会让一段代码同一时刻只能有一个线程使用,多线程同时访问,一个使用其余都是等待状态,那么就存在一个性能问题。若是理解原子性,又那么牛X,利用原子性写出避免同步的免锁代码,什么synchronized啊,ReentrantLock啊,都是浮云。