1、公平鎖:多個線程之間可以按照線程申請鎖的順序獲取鎖;
2、非公平鎖:多個線程之間獲取鎖的順序不一定按照申請鎖的順序獲得;Synchronized、ReentrantLock默認是非公平鎖,後者可以通過構造參數獲取公平鎖。
3、可重入鎖又叫遞歸鎖:是指在一個同步方法內部調用另外一個同步方法時,獲得的鎖是同一把鎖,避免死鎖;舉例如下:
public class TestLock {
public synchronized void hello() {
System.out.println(Thread.currentThread().getName() + "\t 測試遞歸鎖");
//實現的效果就是hello()方法和world()方法總是總一個線程、具有原子性
world();
}
public synchronized void world() {
System.out.println(Thread.currentThread().getName() + "\t 測試遞歸鎖2");
}
public static void main(String[] args) {
TestLock tl = new TestLock();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
tl.hello();
}, String.valueOf(i)).start();
}
}
}
打印結果:
0 測試遞歸鎖
0 測試遞歸鎖2
6 測試遞歸鎖
6 測試遞歸鎖2
4 測試遞歸鎖
4 測試遞歸鎖2
5 測試遞歸鎖
5 測試遞歸鎖2
3 測試遞歸鎖
3 測試遞歸鎖2
2 測試遞歸鎖
2 測試遞歸鎖2
1 測試遞歸鎖
1 測試遞歸鎖2
9 測試遞歸鎖
9 測試遞歸鎖2
8 測試遞歸鎖
8 測試遞歸鎖2
7 測試遞歸鎖
7 測試遞歸鎖2
hello方法和world方法總是一起執行
4、自旋鎖:是指獲取鎖的線程不會立即阻塞,而是利用循環比較的方式去獲取鎖,好處就是減少上下文切換,缺點是循環比較會消耗cpu的性能,舉例如下:
public class TestLock2 {
//利用在這個原子類中存入當前線程,爲獲取鎖,否則自循環等待其他線程釋放鎖以獲得鎖
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void lock() {
Thread thread = Thread.currentThread();
//比較替換成功取反爲false跳出循環
while (!atomicReference.compareAndSet(null, thread)) {
}
System.out.println(thread.getName() + "\t come in");
}
public void unlock() {
Thread thread = Thread.currentThread();
//釋放鎖就是將值爲當線程的內存值更新爲null,好讓下一個線程獲取鎖
atomicReference.compareAndSet(thread, null);
System.out.println(thread.getName() + "\t come out");
}
public static void main(String[] args) {
TestLock2 tl = new TestLock2();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
tl.lock();
try {
//模擬每個線程進來需要消耗1秒鐘
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
tl.unlock();
}
}, String.valueOf(i)).start();
}
}
}
打印結果:
0 come in
0 come out
6 come in
6 come out
4 come in
4 come out
2 come in
2 come out
9 come in
9 come out
8 come in
8 come out
7 come in
7 come out
1 come in
1 come out
5 come in
5 come out
3 come in
3 come out
取得了獲取鎖,釋放鎖的效果
5、獨佔鎖:一次只能被一個線程擁有;共享鎖:一次可以被多個線程共有;其中讀讀是共享,寫讀、讀寫、寫寫都互斥
舉例如下:
public class TestLock3 {
Map<String, Object> params = new HashMap<>();
ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
/**
* 讀共享
*
* @param k
* @return
*/
public Object get(String k) {
rw.readLock().lock();
Object value = null;
try {
value = params.get(k);
System.out.println(Thread.currentThread().getName() + "\t 讀到的值" + value);
} catch (Exception e) {
e.printStackTrace();
} finally {
rw.readLock().unlock();
}
return value;
}
/**
* 寫互斥
*
* @param key
* @param value
* @return
*/
public boolean setParams(String key, Object value) {
rw.writeLock().lock();
if (value == null) {
return false;
}
try {
params.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t key=" + key);
} catch (Exception e) {
e.printStackTrace();
} finally {
rw.writeLock().unlock();
}
return true;
}
public static void main(String[] args) {
TestLock3 testLock3 = new TestLock3();
//多線程寫
for (int i = 0; i < 10; i++) {
final int a = i;
new Thread(() -> {
testLock3.setParams(String.valueOf(a), UUID.randomUUID().toString().substring(0, 3));
}, String.valueOf(i)).start();
}
//先讓寫線程進行
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//多線程讀
for (int i = 0; i < 10; i++) {
final int b = i;
new Thread(() -> {
testLock3.get(String.valueOf(b));
}, String.valueOf(i)).start();
}
}
}