21、各种锁理解
1、公平锁和非公平锁:
公平锁:非常公平,不能够插队,必须先来后到!FIFO
非公平锁:非常不公平,可以插队(默认都是非公平)
2、可重入锁
递归锁
可重入锁synchronized 版本
package com.xing.lock;
//Synchorized
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(); //这里也有锁(sms锁 里面的call锁)
}
public synchronized void call(){
System.out.println(Thread.currentThread().getName() + "call");
}
}
可重入锁Lock版本(递归锁 )
package com.xing.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo02 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
new Thread(()->{
phone.sms();
},"a").start();
new Thread(()->{
phone.sms();
},"b").start();
}
}
class Phone2{
Lock lock = new ReentrantLock();
public void sms(){
lock.lock();//细节问题 第一把锁
//lock锁必须配对否则就会死在里面
try {
System.out.println(Thread.currentThread().getName() + "sms");
call(); //这里也有锁(sms锁 里面的call锁)
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public synchronized void call(){
lock.lock();//第二把锁
try {
System.out.println(Thread.currentThread().getName() + "call");
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
总结:两个锁只要获得外面的锁之后,就能够拿到里面的锁,Lock和synchronized 的区别在需要手动释放锁,并且枷锁的次数和释放的次数要一样
3、自旋锁( spinlock )
不断尝试直到成功为止
自己创建一个自己的锁用CAS完成
package com.xing.lock;
import java.util.concurrent.atomic.AtomicReference;
//自己写的自旋锁
public class SpinlockDemo {
//Thread null
AtomicReference<Thread> atomicReference = new AtomicReference();
// 加锁
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "==>mylock");
//自旋锁
while (!atomicReference.compareAndSet(null, thread)) {
}
}
// 解锁
public void myUnLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "==>myunlock");
atomicReference.compareAndSet(thread, null);
}
}
然后去用线程调用
package com.xing.lock;
import java.util.concurrent.TimeUnit;
public class TestSpinlock {
public static void main(String[] args) {
/*ReentrantLock reentrantLock = new ReentrantLock();
reentrantLock.lock();
reentrantLock.unlock();*/
//底层的是自旋锁CAS实现的
SpinlockDemo spinlockDemo = new SpinlockDemo();
new Thread(()->{
spinlockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
spinlockDemo.myUnLock();
}
},"T1").start();
//T1获得锁,T2一直在自旋。T1解锁后,T2才获得锁结束自旋
new Thread(()->{
spinlockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
spinlockDemo.myUnLock();
}
},"T2").start();
}
}
总结:B线程这里一定会等待T1完成比较交换这个时候自旋锁里已经被A占着了(自旋锁条件:线程不为空及自转)所以B线程会一直自旋到A线程完成CAS的比较交换完成才不在进行自旋操作再进入到myunlock里完成解锁操作
优点:
自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。
缺点:
如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高。
上面Java实现的自旋锁不是公平的,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。
4、死锁
死锁测试,怎么排除死锁
package com.xing.lock;
import single.LazyMan;
import java.util.concurrent.TimeUnit;
public class DeadlockDemo {
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
// A想拿B
new Thread(new MyThread(lockA,lockB),"T1").start();
// B想拿A
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){
//lockA想拿B
System.out.println(Thread.currentThread().getName() + "lock"+ lockA + "=> get" + lockB);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
//B想拿A
System.out.println(Thread.currentThread().getName() + "lock" + lockB + "=> get" + lockA);
}
}
}
}
死锁排查
1、使用jps -l定位进程号
例如:在终端输入jps -l
2、使用jstack 进程号 找到死锁问题
例如:jstack 11444
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/281531.html