java 可重入锁
Posted 偶像java练习生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 可重入锁相关的知识,希望对你有一定的参考价值。
1.公平锁,非公平锁
公平锁:非常公平,不能插队,必须先来后到!
非公平锁:非常不公平,可以插队,例子:一个线程3s 执行完,一个线程3h 执行完,先让3s 的执行,需要插队!
Lock lock = new ReentrantLock();
public ReentrantLock() {
sync = new NonfairSync();
}
ReentranLock 默认是非公平锁
但是可以通过他的构造方法改变为公平锁: 如下
Lock lock = new ReentrantLock(true);
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
synchronized 锁也是非公平锁,所有的锁默认都是非公平锁,保证我们一个效率问题。
2. 可重入锁
所有的锁都是可重入锁,拿到外面的锁之后,就可以拿到里面的锁,自动获得
代码如下:
package com.lock;
//Synchronized
public class Demo01 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{
phone.sms();
},"B").start();
}
}
class Phone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName()+"sms");
call();//这里面也有锁
}
public synchronized void call(){
System.out.println(Thread.currentThread().getName()+"call");
}
}
输出结果:
Asms
Acall
Bsms
Bcall
A 拿到锁后先执行完毕,再B 执行
下面是LOCK 版的:
package com.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo02 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{
phone.sms();
},"B").start();
}
class Phone2{
Lock lock = new ReentrantLock();
public synchronized void sms(){
lock.lock();//细节问题:lock.lock 是拿的两把锁,lock.lock;,lock.unlock
lock.lock()
//lock 锁必须配对,否则就会死在里面
try {
System.out.println(Thread.currentThread().getName()+"sms");
call();//这里面也有锁
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
lock.unlock();
}
}
public synchronized void call(){
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"call");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
输出结果:
Asms
Acall
Bsms
Bcall
3.自旋锁
spinlock
自旋锁:不断的去尝试,直到成功为止!
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
我们来自定义下自旋锁:
package com.lock;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TestSpinLock {
public static void main(String[] args) throws InterruptedException {
// ReentrantLock reentrantLock = new ReentrantLock();
// reentrantLock.lock();
// reentrantLock.unlock();
//底层使用的自旋锁
SpinLockDemo lock = new SpinLockDemo();
new Thread(()->{
try {
lock.myLock();
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.myUnLock();
}
},"T1").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
try {
lock.myLock();
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.myUnLock();
}
},"T2").start();
lock.myLock();
lock.myUnLock();
}
}
输出结果:
T1===> mylock
main===> mylock
T2===> mylock
T1==>myUnlock
T2==>myUnlock
main==>myUnlock
T1 解锁后T2 才能解锁,T1 在自旋,T1 解锁后,T2 解锁
4.死锁
死锁测试,怎么排除死锁:
package com.lock;
import java.util.concurrent.TimeUnit;
public class DeadLockDemo {
public static void main(String[] args) {
String lockA ="lockA";
String lockB ="lockB";
new Thread(new MyThread(lockA,lockB),"T1").start();
new Thread(new MyThread(lockB,lockA),"T2").start();
}
}
class MyThread implements Runnable{
private String lockA;
private String lockB;
public MyThread(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>get"+lockB);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA );
}
}
}
}
输出结果:
T2lock:lockB=>getlockA
T1lock:lockA=>getlockB
程序卡住了
解决程序卡住了的问题
1.使用jps 定位进程号
linux ls-l
而jps 则用jps -l 命令如下:
F:\\workSpace\\AWT>jps -l
2128 sun.tools.jps.Jps
2344 com.lock.DeadLockDemo
8024
15100 org.jetbrains.jps.cmdline.Launcher
可以查看到当前死锁的进程为 2344
- 使用 jstack 进程号 进程号找到死锁问题
使用命令 jstack -2344 显示如下,翻到最底下:
面试或者工作中! 排查问题:
1.进程卡了看上线上有没有异常?
异常: - 使用日志查看
- 使用堆栈,信息
如何解决死锁?
解决死锁产生的条件就可以了!
以上是关于java 可重入锁的主要内容,如果未能解决你的问题,请参考以下文章