为什么80%的码农都做不了架构师?>>>
先说说重入锁,既然说到了重入锁,那么也顺带提一下不可重入锁(自旋锁)吧。
这两个概念实际上很好区分,
重入锁:
就如同在饭堂打饭,你在窗口排着队。排到你的时候,突然路人A让你顺带着打个饭吧,然后你就打了两份饭,这时候你还没离开窗口,又有路人B让你打一份汤,于是你又额外打了一份汤。
即:可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。(本来想自己总结一下,发现不靠谱)
在Java中,ReentrantLock和Synchronized都是可重入锁。
/**
* Created by Anur IjuoKaruKas on 2017/11/14.
* Description :
*/
public class Restaurant {
private Lock windows = new ReentrantLock();
public void getMeals() throws Exception {
try {
windows.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "打饭");
} finally {
windows.unlock();
}
}
public void getSoup() throws Exception {
try {
windows.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "打汤");
} finally {
windows.unlock();
}
}
public void today() throws Exception {
try {
windows.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "打饭");
getMeals();
getSoup();
} finally {
windows.unlock();
}
}
public static void main(String[] args) {
Restaurant test = new Restaurant();
new Thread(() -> {
try {
test.today();
} catch (Exception e) {
e.printStackTrace();
}
}, "我").start();
new Thread(() -> {
try {
test.getSoup();
} catch (Exception e) {
e.printStackTrace();
}
}, "某人").start();
new Thread(() -> {
try {
test.getMeals();
} catch (Exception e) {
e.printStackTrace();
}
}, "另一个人").start();
}
}
输出:
我打饭
我打饭
我打汤
某人打汤
另一个人打饭
不可重入锁(自旋锁):
在另一个菜式比较好吃且热门的窗口,可不是这样的,在这里你在窗口,只能点一个菜(进入一次临界区),点完后,你想要再点别的菜,只能重新排一次队(虽然可以插队,当然我们可以引入服务员队伍管理机制:private Lock windows = new ReentrantLock(true);,指定该锁是公平的。)
即:自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分。
public class Restaurant {
boolean isLock = false;
public synchronized void getMeals() throws Exception {
while (isLock) {
wait();
}
isLock = true;
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "打饭");
} finally {
isLock = false;
}
}
public synchronized void getSoup() throws Exception {
while (isLock) {
wait();
}
isLock = true;
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "打汤");
} finally {
isLock = false;
}
}
public void today() throws Exception {
while (isLock) {
wait();
}
isLock = true;
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "打饭");
getSoup();
} finally {
isLock = false;
}
}
public static void main(String[] args) {
Restaurant test = new Restaurant();
new Thread(() -> {
try {
test.today();
} catch (Exception e) {
e.printStackTrace();
}
}, "我").start();
new Thread(() -> {
try {
test.getSoup();
} catch (Exception e) {
e.printStackTrace();
}
}, "某人").start();
new Thread(() -> {
try {
test.getMeals();
} catch (Exception e) {
e.printStackTrace();
}
}, "另一个人").start();
}
}
输出:
我打饭
然后死锁了……
读写锁:
然而餐次的人流量一大,老板发现经常排起很长的队伍,厨师却都闲着没事干。老板拍脑子一想,这样不行啊,所以稍微改进了一下点餐方式。所有人都可以扫二维码用H页进行点餐,只要这个菜不是正在做(写锁),那么就可以随便点。
即:假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。
/**
* Created by Anur IjuoKaruKas on 2017/11/14.
* Description :
*/
public class Restaurant {
private ReentrantReadWriteLock food = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.ReadLock getFoodLock = food.readLock();
private ReentrantReadWriteLock.WriteLock cookingLock = food.writeLock();
public void getFood() throws Exception {
try {
getFoodLock.lock();
System.out.println(Thread.currentThread().getName() + "点饭");
} finally {
getFoodLock.unlock();
}
}
public void cooking() throws Exception {
try {
cookingLock.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "做菜");
} finally {
cookingLock.unlock();
}
}
public static void main(String[] args) {
Restaurant test = new Restaurant();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
test.getFood();
} catch (Exception e) {
e.printStackTrace();
}
}, "某人").start();
if (i == 2) {
new Thread(() -> {
try {
test.cooking();
} catch (Exception e) {
e.printStackTrace();
}
}, "厨师").start();
}
}
}
}
输出:
某人点饭
某人点饭
某人点饭
厨师做菜
==等待1秒==
某人点饭
某人点饭
某人点饭
某人点饭
某人点饭
某人点饭
某人点饭