我的原则:先会用再说,内部慢慢来
一、 概念
- 不可重入锁是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,此时会阻塞。 Lock 属于不可重入锁。
- 可重入锁,也叫做递归锁,上面情况不阻塞。 ReentrantLock 与 Sychronizded 属于可以重入锁。
二、 实战代码
- (不可重入锁)sun.misc.Lock
import sun.misc.Lock;
public class _08_00_TestLock {
Lock lock = new Lock();
public void print() throws InterruptedException {
System.out.println("do print");
lock.lock();
doAdd();
System.out.println("unlock do print");
lock.unlock();
}
public void doAdd() throws InterruptedException {
System.out.println("do add");
lock.lock();
System.out.println("unlock do add");
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
_08_00_TestLock testLock = new _08_00_TestLock();
testLock.print();
}
}
输出:
do print
do add
(程序一直阻塞)
- (可重入锁)java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class _08_01_TestReentrantLock {
Lock lock = new ReentrantLock();
public void print() throws InterruptedException {
System.out.println("do print");
lock.lock();
doAdd();
System.out.println("unlock do print");
lock.unlock();
}
public void doAdd() throws InterruptedException {
System.out.println("do add");
lock.lock();
System.out.println("unlock do add");
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
_08_01_TestReentrantLock testLock = new _08_01_TestReentrantLock();
testLock.print();
}
}
输出:
do print
do add
unlock do add
unlock do print
- (可重入锁) Synchronized
public class _08_02_TestSynchronized {
public synchronized void print() {
System.out.println("do print");
doAdd();
System.out.println("unlock do print");
}
public synchronized void doAdd(){
System.out.println("do add");
System.out.println("unlock do add");
//do something
}
public static void main(String[] args) throws InterruptedException {
_08_02_TestSynchronized testLock = new _08_02_TestSynchronized();
testLock.print();
}
}
输出:
do print
do add
unlock do add
unlock do print
- (可重入锁) Synchronized(测试一下父类也可重入)
public class _08_03_TestSynchronized {
public static void main(String[] args) {
Child child = new Child();
child.print();
}
}
class Child extends Father{
public synchronized void print() {
System.out.println("Child do print");
doAdd();
System.out.println("Child unlock do print");
}
}
class Father{
public synchronized void doAdd(){
System.out.println("Father do add");
System.out.println("Father unlock do add");
}
}
输出:
Child do print
Father do add
Father unlock do add
Child unlock do print
三、 Thread.interrupt() 中断线程也不会释放锁
public class _08_05_SynchronizedBlocked implements Runnable{
public synchronized void test() {
System.out.println(Thread.currentThread() + " test begin ");
while(true){
if(Thread.currentThread().isInterrupted()){
Thread.yield(); // yield 也是不释放锁的
System.out.println(Thread.currentThread() + " is Interrupted .. but do not release lock .");
}else {
System.out.println(Thread.currentThread() + "normal ");
}
}
}
public void run() {
System.out.println(Thread.currentThread() + " enter run ");
test();
}
public static void main(String[] args) throws InterruptedException {
_08_05_SynchronizedBlocked sync = new _08_05_SynchronizedBlocked();
Thread t1 = new Thread(sync,"AA");
Thread t2 = new Thread(sync,"BB");
//启动后调用f()方法,无法获取当前实例锁处于等待状态
t1.start();
t2.start();
Thread.sleep(1);
//中断线程,无法生效
t1.interrupt();
// 终止线程,可以生效,但是不利于安全
// t1.stop();
System.out.println("t1.interrupt() send ...");
}
}
输出:
Thread[AA,5,main] enter run
Thread[BB,5,main] enter run
Thread[AA,5,main] test begin
Thread[AA,5,main]normal
Thread[AA,5,main]normal
Thread[AA,5,main]normal
t1.interrupt() send ...
Thread[AA,5,main] is Interrupted .. but do not release lock .
Thread[AA,5,main] is Interrupted .. but do not release lock .
Thread[AA,5,main] is Interrupted .. but do not release lock .
...
结论:
- AA 线程启动了,并且进入了synchronized test()方法,然后BB线程启动了,阻塞住了,进不去test()。
- Main线程 interrupt 了AA线程
- AA线程依旧我行我素,不释放锁。
四、 Thread.stop() 中断线程会释放锁
t1.stop(); 代替 t1.interrupt();
输出:
Thread[AA,5,main] enter run
Thread[AA,5,main] test begin
Thread[BB,5,main] enter run
Thread[BB,5,main] test begin
t1.interrupt() send ...
Thread[BB,5,main]normal
Thread[BB,5,main]normal
Thread[BB,5,main]normal
但是,stop不建议使用,我们看看注释。
/*** @deprecated This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
* <code>ThreadDeath</code> exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to
* other threads, potentially resulting in arbitrary behavior. Many
* uses of <code>stop</code> should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), the <code>interrupt</code> method should be used to
* interrupt the wait.
* For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated
public final void stop()
这个方法是不安全的,因为stop会解锁所有monitor,会导致不一致的状态。
举个例子说,threadA线程拥有了monitor,这些监视器负责保护某些临界资源,比如说银行的转账的金额。当正在转账过程中,main线程调用 threadA.stop()方法。结果导致监视器被释放,其保护的资源(转账金额)很可能出现不一致性。比如,A账户减少了100,而B账户却没有增加100。
五、 番外篇
下一章节:【线程】ReentrantLock 实战 (七)
上一章节:Thread.sleep 与 Thread.yield 的区别 (五)