独占锁(排他锁/写锁/X锁/行级):指该锁一次只能被一个线程锁持有,只允许该线程写与读,不允许其他线程加任何锁进行读和写,ReentrantLock和sync而言都是独占锁。
共享锁(读锁/S锁/表级):指该锁可被多个线程所持有,直到释放所有S锁才可以获取排他锁。
读写锁:ReentrantReadWriteLock,表示以上两个锁
读写锁特点:
- 读-读能共享
- 读-写互斥
- 写-读互斥
- 写-写互斥
LockSupport
二元信号量做的线程阻塞工具类,要注意的是,这个信号量最多只能加到1,可以让线程在任意位置阻塞,当然阻塞之后肯定得有唤醒的方法。有park停车和unpark方法,park和unpark可以实现类似wait和notify的功能,不会出现死锁的情况,底层其实都是依赖Unsafe实现。
面试题:两个线程交替输出
注意,unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个“许可”,那么当线程A调用park时,它发现已经有“许可”了,那么它会马上再继续运行。“许可”是一次性的。不像object.wait和notify有先后调用顺序,notify/notyfAll必须在wait之后执行,lockSuppoort不再需要关心对方的状态。, 另外,和wait方法不同,执行park进入休眠后并不会释放持有的锁。park方法不会抛出InterruptedException,但是它也会响应中断 https://blog.csdn.net/u013332124/article/details/84647915
线程的Thread.join 含义: 当前线程A等待thread线程终止之后才能从thread.join()返回
ReentrantReadWriteLock 读写锁详解
现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源;但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写的操作了。
针对这种场景,JAVA的并发包提供了ReentrantReadWriteLock读写锁,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁
public class MyTask {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read() {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " start");
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
public void write() {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + " start");
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
}
public class ReadReadTest {
public static void main(String[] args) {
final MyTask myTask = new MyTask();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
myTask.read();
}
});
t1.setName("t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
myTask.write();
}
});
t2.setName("t2");
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}