可重入锁
也叫可递归锁,当同一线程再次进入同步代码时,可以使用自己已获取到的锁;其目的是当同一线程多次获取到的是同一把锁能防止死锁的发生
代码展示
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest implements Runnable {
private Lock lock = new ReentrantLock();
public void get() {
lock.lock();
System.out.println("get方法的线程id: " + Thread.currentThread().getId());
set();
lock.unlock();
}
public void set() {
lock.lock();
System.out.println("set方法的线程id: " + Thread.currentThread().getId());
lock.unlock();
}
@Override
public void run() {
get();
}
public static void main(String[] args) {
LockTest lockTest = new LockTest();
new Thread(lockTest).start();
new Thread(lockTest).start();
}
}
打印展示

公平锁与非公平锁

1.公平锁会维护一个等待队列,多个在阻塞状态等待的线程会被插入到等待队列,在调度时是按所发请求的时间顺序获取锁
2.在无需保证先进先出的情况下,可以使用非公平锁去抢占锁
3.非公平锁性能高于公平锁,但是如果当前线程不是队列的第一个线程就无法获取到锁,这样会增加线程的切换次数
4.如果线程占用(处理)时间远长于线程等待时间,那么使用非公平锁的效率就不太明显,但是使用公平锁会增强业务的可控性
公平锁
代码展示
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
private Lock lock = new ReentrantLock(true);
public void fairLock() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得了锁");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
LockTest lockTest = new LockTest();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName() + "启动");
lockTest.fairLock();
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) threads[i] = new Thread(runnable);
for (int i = 0; i < 10; i++) threads[i].start();
}
}
打印展示

非公平锁
代码展示
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
private Lock lock = new ReentrantLock(false);
public void fairLock() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得了锁");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
LockTest lockTest = new LockTest();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName() + "启动");
lockTest.fairLock();
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) threads[i] = new Thread(runnable);
for (int i = 0; i < 10; i++) threads[i].start();
}
}
打印展示

读写锁
1.ReentrantReadWriteLock(读写锁)对象会使用两把锁管理临界资源,分别是读锁与写锁
2.某线程获得了资源的读锁,其他读操作可以并发,但写操作的线程会被阻塞
3.当读操作的数量远超过写操作时,可以用读写锁使读操作能够并发执行,从而提升性能
代码展示
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockTest {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
private int num;
public void read() {
int i = 0;
while (i++ < 3) {
try {
readLock.lock();
System.out.println(Thread.currentThread().getId() + " 开始读");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getId() + " 读num: " + num);
} catch (Exception e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
}
public void write() {
int i = 0;
while (i++ < 3) {
try {
writeLock.lock();
System.out.println(Thread.currentThread().getId() + " 开始写");
Thread.sleep(1000);
num = (int) (Math.random() * 10);
System.out.println(Thread.currentThread().getId() + " 修改后的num: " + num);
} catch (Exception e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
}
public static class ReadThead extends Thread {
private final LockTest lockTest;
public ReadThead(LockTest lockTest) {
this.lockTest = lockTest;
}
@Override
public void run() {
lockTest.read();
}
}
public static class WriteThead extends Thread {
private final LockTest lockTest;
public WriteThead(LockTest lockTest) {
this.lockTest = lockTest;
}
@Override
public void run() {
lockTest.write();
}
}
public static void main(String[] args) {
LockTest lockTest = new LockTest();
for (int i = 0; i < 3; i++) {
new ReadThead(lockTest).start();
new WriteThead(lockTest).start();
}
}
}
打印展示
12 开始读
12 读num: 0
13 开始写
13 修改后的num: 5
13 开始写
13 修改后的num: 1
13 开始写
13 修改后的num: 7
15 开始写
15 修改后的num: 5
15 开始写
15 修改后的num: 3
15 开始写
15 修改后的num: 4
14 开始读
16 开始读
14 读num: 4
16 读num: 4
17 开始写
17 修改后的num: 2
17 开始写
17 修改后的num: 3
17 开始写
17 修改后的num: 2
12 开始读
14 开始读
16 开始读
14 读num: 2
16 读num: 2
16 开始读
12 读num: 2
12 开始读
14 开始读
14 读num: 2
16 读num: 2
12 读num: 2
Process finished with exit code 0