JUC 详解 -> 各种锁的理解
1. 公平锁、非公平锁
- 公平锁:非常公平,不能插队,必须先来后到
- 非公平锁:非常不公平,可以插队,(默认都是非公平锁)
java的ReenTrantLock就是用队列实现的公平锁和非公平锁。
公平锁中,如果有另一个线程持有锁或者有其他线程在等待队列中等待这个锁,那么新发出请求的线程将被放入到队列中。而非公平锁上,只有当锁被某个线程持有时,新发出请求的线程才会被放入队列中(此时和公平锁是一样的)。所以,它们的差别在于非公平锁会有更多的机会去抢占锁。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
2. 可重入锁
- 可重入锁,也叫递归锁
//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");
}
}
//Lock版
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//ReentrantLock
public class Demo02 {
public static void main(String[] args) {
Phone2 phone2 = new Phone2();
new Thread(()->{
phone2.sms();
},"A").start();
new Thread(()->{
phone2.sms();
},"B").start();
}
}
class Phone2{
Lock lock = new ReentrantLock();
public void sms(){
lock.lock(); //细节问题!两把锁,进到call(),也会拿到一把锁!
//lock.lock(); 死锁
//lock锁必须配对
try{
System.out.println(Thread.currentThread().getName() + " sms");
call();
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void call(){
lock.lock();
try{
System.out.println(Thread.currentThread().getName() + " call");
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
3. 自旋锁
- spinlock
- 自定义自旋锁
import java.util.concurrent.atomic.AtomicReference;
//自旋锁
public class SpinLockDemo {
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);
}
}
- 测试
import java.util.concurrent.TimeUnit;
public class TestSpinLock {
public static void main(String[] args) throws InterruptedException {
//底层使用的是自旋锁CAS
SpinLockDemo lockDemo = new SpinLockDemo();
new Thread(()->{
lockDemo.myLock();
try{
TimeUnit.SECONDS.sleep(5);
}catch (Exception e){
e.printStackTrace();
}finally {
lockDemo.myUnlock();
}
},"T1").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
lockDemo.myLock();
try{
TimeUnit.SECONDS.sleep(1);
}catch (Exception e){
e.printStackTrace();
}finally {
lockDemo.myUnlock();
}
},"T2").start();
}
}
4. 死锁
死锁是什么?
- 四要素:互斥、占有等待、循环等待、不可抢占
死锁测试
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);
}
}
}
}
如何排除死锁,解决问题
- 1 使用 **jps -l **定位进程号
- 2 使用jstack 进程号查看进程信息