生活
我大概是一个暴躁的人,有事就说,有屁就放,磨磨唧唧,支支吾吾真的受不了。
今天很暴躁。!!
场景
下面就来强行写今天的东西。
在并发编程中,有个非常重要的概念 锁。没错很强行。
这里的锁,其实和现实中的锁很相似。
举个有点恶心的例子,上厕所。没错还是强行~
公司有800人,假设只有一个厕所,现在有40人要上厕所,能一起上吗?不能。所以怎么办,排队等待,等到厕所没人了可以进去上厕所,进去以后第一步就是锁门,获取了厕所这个资源,其他人就不能进去上厕所。当里面的人上完厕所,就把门打开,释放了这个资源,然后后面的人就可以获取这个资源了。不过有的人很着急,就插队了!!
在JDK1.5以前,重入锁的性能远远好于synchronized关键字,JDK1.6以后,synchorinized关键字进行了大量的优化,二者性能不相伯仲,但是重入锁几乎可以取代synchronized关键字。除此之外,重入锁还提供了可中断响应、锁申请等待限时、公平锁等机制。另外可以结果条件变量Condition使用。
简述
下面来看看如何创建一个可重入锁。
//默认非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//通过fail指定是否创建公平
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
是否公平其实跟信号量是一个道理,就是在尝试获取资源前先判断有没有已经在等待队列的线程,
如果有就不cas直接进入队列等待,保证公平
如何上锁?
// 不响应中断 不超时
public void lock() {
sync.lock();
}
//响应中断,其实就是加个是否中断的判断罢了
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
//尝试获取,不阻塞,获取到返回true,否杂false
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
//设置超时
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
如何解锁?
public void unlock() {
sync.release(1);
}
其中的代码细节不在赘述,看前面的AQS即可祥知~
另外为什么叫可重入锁呢?
意思是可以重复获取已经获取的锁。只是state+1,上锁几次,就要解锁几次,才能完全释放,其他线程才能去获取!
案例
先看下不加锁的
import java.util.concurrent.CountDownLatch;
public class Counter {
public volatile static int count = 0;
public static void inc() {
//这里延迟5毫秒,使得结果明显
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
count ++;
}
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1000);
//同时启动1000个线程,去进行i++计算,看看实际结果
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
latch.countDown();
}
}).start();
}
latch.await();
//这里每次运行的值都有可能不同,可能为1000
System.out.println("运行结果:Counter.count=" + Counter.count);
}
}
结果:
运行结果:Counter.count=998,是随机的,可能是1000,也可能比1000小,因为volatile 无法保证线程安全。
下面加锁试下:
仅在下面方法加锁,其他代码不变:
public static void inc() {
//这里延迟5毫秒,使得结果明显
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
lock.lock();
count ++;
lock.unLock();
}
此时运行几次都是:
运行结果:Counter.count=1000
后记
上文提到的synchronized与Lock的区别以及与条件变量Condition之间的配合使用在后面再去研究了。早点休息~~