一、Java 锁
1.1、公平锁和非公平锁
解释
公平锁解释:多线程情况下,按照申请锁的顺序进行获取锁,先来先得。
非公平锁解释:多线程情况下,获取锁的顺序不是按照申请锁顺序来的。高并发情况下,可能会导致优先级反转或者饥饿现象。
两者区别
公平锁是并发环境下,每个线程获取锁,查看等待队列,如果为空,或线程是等待队列的第一个,则占有锁,否则加入等待队列,按照先进先出规则队列中取到自己。
非公平锁就是上来直接占有锁,尝试失败,在采用公平锁方式。
JAVA 锁
ReentrantLock 属于非公平锁,可以通过构造函数 Booleen值指定,True 公平锁,False 非公平锁。非公平锁优点在于吞吐量比公平锁大
synchronized 也是非公平锁
1.2、可重入锁(递归锁)原理
可重入锁 最大作用是避免死锁
package com.xin;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author :小心仔
* @date :Created in 2021/11/4 18:54
* @description:
*/
public class ReenterLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
System.out.println("================synchronized================");
new Thread(() -> {
phone.sendQQ();
}, "t1").start();
new Thread(() -> {
phone.sendQQ();
}, "t2").start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace();}
System.out.println("================ReentrantLock================");
Thread t3 = new Thread(phone,"t3");
Thread t4 = new Thread(phone,"t4");
t3.start();
t4.start();
}
}
class Phone implements Runnable{
public synchronized void sendQQ() {
System.out.println(Thread.currentThread().getName() + "\t invoke:sendQQ");
sendWeChat();
}
public synchronized void sendWeChat() {
System.out.println(Thread.currentThread().getName() + "\t #####invoke:sendWeChat");
}
@Override
public void run() {
get();
}
Lock lock = new ReentrantLock();
public void get() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t invoke:get");
set();
} finally {
lock.unlock();
}
}
public void set() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t invoke:set");
} finally {
lock.unlock();
}
}
}
1.3、自旋锁(spinlock)
理论
获取线程的锁不会被阻塞,线程会采用循环的方式获取锁,好处减少上下文切换资源浪费,缺点是循环消耗CPU。
代码
package com.xin;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author :小心仔
* @date :Created in 2021/11/4 19:32
* @description:自旋锁Demo
*/
public class SpinlockDemo {
AtomicReference<Object> atomicReference = new AtomicReference();
public static void main(String[] args) {
SpinlockDemo spinlockDemo = new SpinlockDemo();
new Thread(() -> {
spinlockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
spinlockDemo.myUnlock();
}, "AA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
spinlockDemo.myLock();
spinlockDemo.myUnlock();
}, "BB").start();
}
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "come in");
while (!atomicReference.compareAndSet(null, thread)) {
}
}
public void myUnlock() {
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread, null);
System.out.println(Thread.currentThread().getName() + "invoke out");
}
}
1.3、读写锁
理论
独占锁(写锁):synchronized、ReentrantLock
共享锁(读锁):
互斥锁:ReadWriteLock
代码
读写锁代码
ReentrantReadWriteLock
package com.xin;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author :小心仔
* @date :Created in 2021/11/4 20:01
* @description:
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) {
final int ii = i;
new Thread(() -> {
myCache.set(ii + "", ii + "");
myCache.get(ii + "");
}, String.valueOf(i)).start();
}
}
}
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
public void get(String key) {
reentrantReadWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 进行读取");
TimeUnit.MILLISECONDS.sleep(300);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读取值:" + o);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantReadWriteLock.readLock().unlock();
}
}
public void set(String key, Object value) {
reentrantReadWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 进行写入" + value.toString());
TimeUnit.MILLISECONDS.sleep(300);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 写入成功");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantReadWriteLock.writeLock().unlock();
}
}
}
死锁
产生原因
系统资源不足
资源分配不当
解决办法
jps 命令定位进程号 jps -l
jstack 找到死锁查看 jstack 进程号