前言
上节课我们讲了锁的概念,讲了对象锁和类锁,讲了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以后会详细讲解,尽请期待吧!!!
总结
今天主要讨论了锁的重入与不可重入问题,相信大家对锁有了更深一层的理解。
最后送自己一句话也是送各位朋友的一句话,今天你是谁不重要,重要的是你以后是谁,虽然现在大家看起来都差不多,但是两年、五年后差距就慢慢出来了,学习这种事情就在于积累,你可能学历不高,专业不对口,但你只要肯努力,这一切都不是问题,希望大家都能有所收获,那么我写这篇博客的意义就有了,最后感谢大家百忙中抽出时间来看我写的博客,本人能力有限,可能有些东西描述不太恰当,希望大家多多谅解!!!