独占锁(写锁)、共享锁(读锁)、读写锁

独占锁(排他锁/写锁/X锁/行级):指该锁一次只能被一个线程锁持有,只允许该线程写与读,不允许其他线程加任何锁进行读和写,ReentrantLock和sync而言都是独占锁。

共享锁(读锁/S锁/表级):指该锁可被多个线程所持有,直到释放所有S锁才可以获取排他锁。

读写锁:ReentrantReadWriteLock,表示以上两个锁

读写锁特点:
  1. 读-读能共享
  2. 读-写互斥
  3. 写-读互斥
  4. 写-写互斥
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,但是它也会响应中断 imagehttps://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();
    }
}
原文地址:https://www.cnblogs.com/xhyouyou/p/12465284.html