【线程】可重入锁与不可重入锁(六)

我的原则:先会用再说,内部慢慢来


一、 概念

  1. 不可重入锁是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,此时会阻塞。 Lock 属于不可重入锁。
  2. 可重入锁,也叫做递归锁,上面情况不阻塞。 ReentrantLock 与 Sychronizded 属于可以重入锁。

二、 实战代码

  1. (不可重入锁)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
(程序一直阻塞)
  1. (可重入锁)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
  1. (可重入锁) 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
  1. (可重入锁) 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 .
...

结论:

  1. AA 线程启动了,并且进入了synchronized test()方法,然后BB线程启动了,阻塞住了,进不去test()。
  2. Main线程 interrupt 了AA线程
  3. 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 的区别 (五)

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值