1:公平锁,非公平锁;
公平锁:非常的公平,不能够插队,必须先来厚道。
非公平锁:非常的不公平,可以插队,(默认都是非公平的)
查看底层ReentrantLock 的底层实现,可以自己设置公平锁,和非公平锁;
我们可以看到 ReentrantLock 有一个参数是bollean ,是指为 true 表示获得了公平锁;默认的非公平锁;
public ReentrantLock() {
sync = new NonfairSync();
}
//可以自己设置;
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
2:可重入锁;
Syschronized版
package com.baidu.Lock;
/**
* 一个同步方法可以调用另外一个同步方法,一个线程己经拥有某个对象的锁,
* 再次申请的时候仍然会得到该对象的锁 也就是说synchronized获得的锁是可重入的
*
* synchronized是可重入锁,可以粗浅地理解为同一个线程在已经持有该锁的情况下,
* 可以再次获取锁,并且会在某个状态量上做+1操作
*
*/
import java.util.concurrent.TimeUnit;
//可重入锁;
public class Demo01 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.msg();
},"A").start();
new Thread(()->{
phone.msg();
},"B").start();
}
}
class Phone{
public synchronized void msg(){
System.out.println(Thread.currentThread().getName()+"==>msg");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
call();
}
public synchronized void call(){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"==>call");
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/edb9f1ed1ac641c590b03079152351c2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmVlbiBEb2luZw==,size_20,color_FFFFFF,t_70,g_se,x_16)
Lock版
package com.baidu.Lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockDemo02 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
new Thread(()->{
phone.msg();
},"A").start();
new Thread(()->{
phone.msg();
},"B").start();
}
}
class Phone2{
//这就是一把锁,锁的就是ReentrantLock这个对象,ReenTrantLock中有AQS,AQS可以判断两次lock方法都是同一个线程,这才是可重入锁
Lock lock = new ReentrantLock();
public void msg(){
lock.lock(); //lock锁必须配对;否则会死在里面;
try {
System.out.println(Thread.currentThread().getName()+"==>msg");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
call(); //这里也是又锁的;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public synchronized void call(){
lock.lock();
try {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"==>call");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
3:自旋锁
https://blog.csdn.net/qq_39004307/article/details/102550520
什么是自旋锁:
是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
自旋锁存在的问题:
- 如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高
- 上面Java实现的自旋锁不是公平的,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。
优点:
- 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
- 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。 (线程被阻塞后便进入内核(Linux)调度状态,这个会导致系统在用户态与内核态之间来回切换,严重影响锁的性能)
package com.baidu.Lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
//自己创建一个自旋锁;
// T1获得琐,T2自旋一直尝试获得。T1解锁后,T2才可以获得琐结束自旋,然后解锁
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);
}
public static void main(String[] args) throws InterruptedException {
//底层使用的自旋锁CAS 操作;
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(()->{
spinLockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
} finally {
spinLockDemo.myUnLock();
}
},"t1").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
spinLockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
spinLockDemo.myUnLock();
}
},"t2").start();
}
}
测试结果: 分析:
T1获得琐,T2自旋一直尝试获得。T1解锁后,T2才可以获得琐结束自旋,然后解锁。
自旋锁的底层也是也是用的CAS 操作,
4:死锁
package com.baidu.Lock;
import sun.java2d.loops.TransformHelper;
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);
}
}
}
}
解决方法:
使用 jps -l
使用jstack 加上进程号(4524)