Lock
java.util.concurrent.locks
Interface Lock
所有已知实现类:
ReentrantLock , ReentrantReadWriteLock.ReadLock , ReentrantReadWriteLock.WriteLock
与Snychronized的区别
先看一先Snychronized对锁的把控
1 | /** |
结果:
11:41:35线程a开始运行…
11:41:35线程b开始运行…
11:41:35线程a试图占有对象…
11:41:35线程b试图占有对象…
11:41:35线程a占有对象…
11:41:38线程a释放对象
11:41:38线程a线程结束.
11:41:38线程b占有对象…
11:41:41线程b释放对象
11:41:41线程b线程结束.
接下来就看一下Lock的
1 | /** |
结果:
11:40:48线程b开始运行…
11:40:48线程a开始运行…
11:40:48线程b试图占有对象…
11:40:48线程a试图占有对象…
11:40:48线程b占有对象…
11:40:51线程b占有对象完毕
11:40:51线程b释放对象
11:40:51线程a占有对象…
11:40:51线程b线程结束.
11:40:54线程a占有对象完毕
11:40:54线程a释放对象
11:40:54线程a线程结束.
Lock-线程交互
Synchronize中使用是的
wait()
,notify();
而,Lock使用的子类
ReentrantLock
并没有这两个方法但是我们在官网看对Lock接口的介绍 讲到
public interface Lock
Lock
实现提供比使用synchronized
方法和语句可以获得的更广泛的锁定操作。 它们允许更灵活的结构化,可能具有完全不同的属性,并且可以支持多个相关联的对象Condition
可以看到有这么一个
Condition
我们看一下官方对
Condition
的介绍public interface Condition
Condition因素出Object监视器方法( wait , notify和notifyAll )成不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果Lock个实现。 Lock替换synchronized方法和语句的使用, Condition取代了对象监视器方法的使用。
到这里,可以知道Condition是我们需要的了看一下Conditon的方法
1 | void await() |
可以看出,对应Synchronized的( wait , notify和notifyAll )的Condition方法是 ( await() , signal() , signalAll() ) ;
再看一下官方给出的用法
1 | class BoundedBuffer { |
现在来使用一下
1 | public static void lockConditonTest() { |
结果:
11:40:03线程a开始运行…
11:40:03线程b开始运行…
11:40:03线程b试图占有对象…
11:40:03线程a试图占有对象…
11:40:03线程b占有对象…
11:40:06线程b临时释放对象,并唤醒等待线程…
11:40:06线程a占有对象…
11:40:06线程b释放对象
11:40:06线程b线程结束.
11:40:09线程a临时释放对象,并进行等待2s之后的唤醒
11:40:11线程a等待结束,重新占有
11:40:13线程a释放对象
11:40:13线程a线程结束.
再介绍一下Lock的非阻塞获取锁的方法
Lock实现提供了使用synchronized方法和语句的附加功能,通过提供非阻塞尝试来获取锁( tryLock() ),尝试获取可被中断的锁( lockInterruptibly()) ,以及尝试获取可以超时( tryLock(long, TimeUnit) )。
看代码
1 | public static void trylockTest() { |
结果:
11:44:47线程b开始运行…
11:44:47线程a开始运行…
11:44:47线程b试图占有对象…
11:44:47线程a试图占有对象…
11:44:47线程a占有对象…
试图占领失败,撤退
11:44:49线程b线程结束.
11:44:50线程a占有对象完毕
11:44:50线程a释放对象
11:44:50线程a线程结束.
对于tryLock() ,在释放锁的时候,一定要判断一下是否拿到了锁,要不然会报java.lang.IllegalMonitorStateException
是不是以为到这里就结束了? 不,没有,
对于多线程,知道这是可以充分利用我们的CPU资源,但是如果多个线程都同时对一个变量进行修改,会发生什么?
结果有可能正常:但也有可能不正常;
比如 int i = i ++这行代码,很简单是不是,但是但多个线程访问的时候,你猜猜会发生什么?咱们代码来解释一切问题,请看
1 | static int a = 0; |
结果:
10000个线程后a的值:10000
10000个线程后a的值:9999
10000个线程后a的值:9997
这里运算了3个结果;
虽然加锁可以实现保证得到正确的结果,但这里研究Aomtic就不加锁了
所以这时候就有原子操作出现了
- |
int
|incrementAndGet()
原子上增加一个当前值。 |
| —– | ——————————————- |
| | |
- |
1 | static int a = 0; |
结果:
10000个线程后a的值:9998
10000个线程后atomicA的值:10000
小唠嗑:
本章到这里就结束了,谢谢耐心看到这里的各位Boss,如果觉得有哪里说的不好的地方,还请高抬贵手多多原谅,不惜指教。
最后,谢谢!