Java多线程4:可重入锁与不可重入锁的区别

前言

上节课我们讲了锁的概念,讲了对象锁和类锁,讲了synchronized修饰方法和synchronized代码块的区别,不知道大家有没有消化,在开始新的内容之前,先来做道题,复习下上节课的内容。

实例

public class T implements Runnable {



private int count = 10;



public synchronized void run() { 

    count--;

    System.out.println(Thread.currentThread().getName() + " count = " + count);

}



public static void main(String[] args) {



    for(int i=0; i<5; i++) {

        T t = new T();

        new Thread(t, "THREAD" + i).start();

    }

}



}

这五个线程同时执行还是串行执行(一个线程执行结束下一个线程才开始执行),输出的结果是什么?

大家可以思考思考,下篇博客会给出答案

什么是可重入锁

一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁

常用的可重入锁有Synchronize以及我们以后会提到的ReentrantLock都是可重入锁

什么是不可重入锁

即当前线程获取这把锁后,要想再拿到这把锁,必须释放当前持有的锁,这时我们称这个锁是不可重入的。

模拟锁的不可重入

public class Lock{

//默认情况下表示当前锁处于未锁定状态
private boolean isLocked = false;

public synchronized void lock() throws InterruptedException{

    //若处于锁定状态,表示当前有其他线程获取到了锁,则进入等待池,等待其他线程释放锁
    while(isLocked){    

        wait();

    }
    //此时表示该线程已经获取锁,并将锁设置为锁定状态
    isLocked = true;

}

public synchronized void unlock(){
    //当前线程将锁释放,并将锁设置为未锁定状态
    isLocked = false;
    //唤醒其他处于等待队列的线程
    notify();

}

}

测试不可重入锁

public class Count{

Lock lock = new Lock();

public void print(){

    try {

        lock.lock();

        System.out.println("print....");

        doAdd();

    } catch (InterruptedException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }finally {

        lock.unlock();

    }   

}

public void doAdd(){

    try {

        lock.lock();

        System.out.println("doAdd....");

        lock.unlock();

    } catch (InterruptedException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }

}



public static void main(String[] args) {



    Count count=new Count();

    new Thread(new Runnable() {



        @Override

        public void run() {

            // TODO Auto-generated method stub



            count.print();

        }

    }).start();



}

}

打印结果

print….

这里自定义实现了一把不可重入锁,这里在print方法中执行doAdd方法时会发现线程会进入等待池中等待锁的释放

接下来我们再看看可重入锁的执行过程

public class T {

synchronized void m1() {

    System.out.println("m1 start");

    try {

        TimeUnit.SECONDS.sleep(1);

    } catch (InterruptedException e) {

        e.printStackTrace();

    }

    m2();

}



synchronized void m2() {

    try {

        TimeUnit.SECONDS.sleep(2);

    } catch (InterruptedException e) {

        e.printStackTrace();

    }

    System.out.println("m2");

}

public static void main(String[] args) {



    new T().m1();



}



}

打印结果

m1 start

m2

明显可以看出synchronized锁是可重入的

另一种可重入锁

public class Count{



ReentrantLock lock = new ReentrantLock();

//Lock lock = new Lock();





public void print() throws InterruptedException{

    try {

        lock.lock();

        System.out.println("print....");

        doAdd();

    }finally {

        lock.unlock();

    }   

}

public void doAdd() throws InterruptedException{

    lock.lock();

    System.out.println("doAdd....");

    lock.unlock();

}



public static void main(String[] args) {



    Count count=new Count();

    new Thread(new Runnable() {



        @Override

        public void run() {

            // TODO Auto-generated method stub



            try {

                count.print();

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

    }).start();



}

}

打印结果

print….

doAdd….

这里可以看到线程在获取完这把锁后还可以继续尝试获取,这里的ReentrantLock以后会详细讲解,尽请期待吧!!!

总结

今天主要讨论了锁的重入与不可重入问题,相信大家对锁有了更深一层的理解。

最后送自己一句话也是送各位朋友的一句话,今天你是谁不重要,重要的是你以后是谁,虽然现在大家看起来都差不多,但是两年、五年后差距就慢慢出来了,学习这种事情就在于积累,你可能学历不高,专业不对口,但你只要肯努力,这一切都不是问题,希望大家都能有所收获,那么我写这篇博客的意义就有了,最后感谢大家百忙中抽出时间来看我写的博客,本人能力有限,可能有些东西描述不太恰当,希望大家多多谅解!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值