- 公平锁 表示线程获取锁的的顺序是按照线程加锁的顺序来分配的
- 非公平锁 随机获得
并发包中ReentrantLock 的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认非公平锁。
非公平锁优点是比公平锁吞吐量大
synchronized也是一种非公平锁
可重入锁(又名递归锁):
指的是同一线程外层函数获得锁之后,内层递归函数仍能获得该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁
: 线程可以进入任何一个他所拥有锁同步着的代码块
可重入锁最大作用是 避免死锁
ReentrantLock 和 synchronized 都是可重入锁
自旋锁:
是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU、
//sun.misc.Unsafe
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
//var5 = 当前这个对象这个地址上的值是多少
var5 = this.getIntVolatile(var1, var2);
//如果当前对象这个地址的值和上面获取的var5一样,就加var4
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
//修改成功,返回true,跳出循环
//判断这个值被别人改过了,不是我们获取的期望值了,返回false,继续循环,再获取最新值,直到比较成功
return var5;
}
模仿写自旋锁:
public class SyncList {
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void myLock() {
System.out.println(Thread.currentThread().getName() + "comming in");
//AA修改后,原子引用有值,不为null,判断不成立,返回false,一直进入循环
while(! atomicReference.compareAndSet(null, Thread.currentThread())) {
}
}
public void myUnlock() {
atomicReference.compareAndSet(Thread.currentThread(), null);
System.out.println(Thread.currentThread().getName() + "invoke myUnlock");
}
public static void main(String[] args) {
SyncList syncList = new SyncList();
new Thread(() -> {
syncList.myLock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
syncList.myUnlock();
}, "AA").start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
syncList.myLock();
syncList.myUnlock();
}, "BB").start();
}
}
AAcomming in
BBcomming in
AAinvoke myUnlock
BBinvoke myUnlock
独占锁(写锁): 该锁一次只能够被一个线程所持有 ReentrantLock/synchronized,ReentrantReadWriterLock 的写锁
共享锁(读锁): 该锁可以被多个线程共有 ReentrantReadWriterLock 的读锁
互斥锁
ReentrantReadWriterLock lock = new ReentrantReadWriterLock();
...
lock.readLock().lock(); //获取读锁
... //允许多个线程同时进入lock()后面的代码
lock.readLock.unLock();
lock.writeLock().lock(); //获取写锁
... //同一时间只允许一个线程执行lock()后面的代码
lock.writeLock().unLock();
读写锁互斥例子:
class MyCache{
private volatile Map<String, Object> map = new HashMap<>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + " put key:" + key + " value:" + value);
TimeUnit.SECONDS.sleep(2);
map.put(key, value);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public void get(String key) {
try {
lock.readLock().lock();
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + " get key:" + key + " value:" + map.get(key));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
public class Lock {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
myCache.put(finalI +"", finalI +"");
}, "put" + String.valueOf(i)).start();
}
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
myCache.get(String.valueOf(finalI));
}, "getA" + String.valueOf(i)).start();
}
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
myCache.get(String.valueOf(finalI));
}, "getB" + String.valueOf(i)).start();
}
}
}
put0 put key:0 value:0
put1 put key:1 value:1
put2 put key:2 value:2
put3 put key:3 value:3
put4 put key:4 value:4
getA0 get key:0 value:0
getB3 get key:3 value:3
getB4 get key:4 value:4
getA2 get key:2 value:2
getA1 get key:1 value:1
getB2 get key:2 value:2
getB1 get key:1 value:1
getB0 get key:0 value:0
getA4 get key:4 value:4
getA3 get key:3 value:3