当咱们了解了多线程生成的缘由以后,会有相应的解决办法,最典型的就是 synchronized 和 lock。lock能够说是 synchronized 的一个替代品,synchronized 能作的事,lock 基本均可以作,并且能作得更好。他们的一些区别是:java
这样能够看到,lock 比起 synchronized 具备更细粒度的控制。可是也不是说 lock 就彻底能够取代 synchronized,由于 lock 的学习成本,复杂度等方面要比 synchronized 高,对于初级 java 程序员,使用 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(); }
lock() 能够用于对一段代码进行加锁,这样别的代码在锁释放以前须要进行等待,须要注意,lock不会像 synchronized 那样自动释放锁,因此:必定要放在 try-finally块中,保证锁的释放。 例如:并发
try { lock.lock(); ...... } finally { lock.unlock(); }
这里首先须要了解两个概念才能更好的理解这个方法:函数
对于线程的打扰机制,每一个线程都有一个打扰标志。源码分析
因此说,对于 interrupt() 方法:不会中断一个正在运行的线程。学习
对于 interrupt,interrupted,isInterrupted方法的区别:this
interrupt 方法上面有说到了。对于 interrupted 和 isInterrupted 方法,stackoverflow 说得很好了:线程
interrupted() is static and checks the current thread. isInterrupted() is an instance method which checks the Thread object that it is called on.code
A common error is to call a static method on an instance.
Thread myThread = ...; if (myThread.interrupted()) {} // WRONG! This might not be checking myThread. if (myThread.isInterrupted()) {} // Right!
Another difference is that interrupted() also clears the status of the current thread. In other words, if you call it twice in a row and the thread is not interrupted between the two calls, the second call will return false even if the first call returned true.
The Javadocs tell you important things like this; use them often!
下面再介绍下 lockInterruptibly 方法:
当经过这个方法去获取锁时,若是线程正在等待获取锁,则这个线程可以响应中断,即中断线程的等待状 态。例如当两个线程同时经过lock.lockInterruptibly()想获取某个锁时,倘若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法可以中断线程B的等待过程。
用于获取一个 Conodition 对象。Condition 对象是比 Lock 更细粒度的控制。要很好的理解 condition,我的以为必需要知道,生产者消费者问题。
简单来讲就是,咱们都了解生产者在缓冲区满了的时候须要休眠,此时会再唤起一个线程,那么你此时唤醒的是生成者仍是消费者呢,若是是消费者,很好;可是若是是唤醒生产者,那还要再休眠,此时就浪费资源了。condition就能够用来解决这个问题,能保证每次唤醒的都是消费者。具体参考:Java 多线程:condition关键字
lock 方法大致就介绍到这里。
可重入锁:指同一个线程,外层函数得到锁以后,内层递归函数仍有得到该锁的代码,可是不受影响。
**可重入锁的最大做用就是 能够避免死锁。**例如:A线程有两个方法 a 和 b,其中 a 方法会调用 b 方法,假如 a,b 两个方法都须要得到锁,那么首先 a 方法先执行,会得到锁,此时 b方法将永远得到不了锁,b 方法将一直阻塞住, a 方法因为 b 方法没有执行完,它自己也 不释放锁,此时就会形成一个死锁。 ReentrantLock 就是一个可重入锁。真正使用锁的时候,通常是 Lock lock = new ReentrantLock();而后 使用 Lock 接口方法。
接口代码以下:
public interface ReadWriteLock { Lock readLock(); Lock writeLock(); }
ReadWriteLock 能够算是 Lock 的一个细分,合理使用有利于提升效率。好比说, 对于一个变量 i, A,B 线程同时读,那么不会形成错误的结果,因此此时是容许并发,可是若是是同时写操做,那么则是有可能形成错误。因此真正使用的时候,可使用细分须要的是读锁仍是写锁,再相应地进行加锁。
Ps:从代码也能够看出,ReadWriteLock 和 Lock 没有关系,既不继承,也不是实现。