0
点赞
收藏
分享

微信扫一扫

Java并发工具J.U.C1

悬灸人雪洋 2022-02-18 阅读 65

文章目录

Lock (Synchronized)

在Lock接口出现之前,Java中的应用程序对于多线程的并发安全处理只能基于synchronized关键字来解决。但是synchronized在有些场景中会存在一些短板,也就是它并不适合于所有的并发场景。但是在 Java5以后,Lock的出现可以解决synchronized在某些场景中的短板,它比synchronized更加灵活。

public class AtomicDemo {
    private static int count=0;
    static Lock lock=new ReentrantLock();
    public static void inc(){
        lock.lock(); //获得锁(互斥锁)
        try {
            Thread.sleep(1);
            count++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁 
        }
    }
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000; i++) {
            new Thread(()->AtomicDemo.inc()).start();
        }
        Thread.sleep(4000);
        System.out.println("result:"+count);
    }
}

输出结果:

result:1000

ReentrantLock(重入锁)

ReentrantLock是一种互斥锁。
重入锁:已经获得锁的线程,在不释放锁的前提下可以再次获得锁。
例如:

public class AtomicDemo {

    private static int count=0;

    //重入锁(如何实现的?)
    static Lock lock=new ReentrantLock(true);

    public static void inc(){
        lock.lock(); //获得锁(互斥锁) ThreadA 获得了锁
        try {
            Thread.sleep(1);
            count++;
            decr();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁 ThreadA释放锁  state=1-1=0
        }
    }
    public static void decr(){
        lock.lock(); //state=2   //ThreadA再次来抢占锁 : 不需要再次抢占锁,而是只增加重入的次数
        try{
            count--;
        }finally {
            lock.unlock(); //state=1
        }
    }
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000; i++) {
            new Thread(()->AtomicDemo.inc()).start();
        }
        Thread.sleep(4000);
        System.out.println("result:"+count);
    }
}

假如锁不能重入,ThreadA在调用inc()方法时,将会出现死锁。因为A第一次已经获得了锁,在调用decr()时候如果获取不到锁就会发生阻塞,从而死锁。

ReentrantReadWriteLock(重入读写锁)

适用于读多写少的情况下.
1、读和读不互斥
2、读和写互斥
3、写和写互斥
ReentrantReadWriteLock里面维护了2把锁,一把读锁,一把写锁。

public class Demo {
    static Map<String,Object> cacheMap=new HashMap<>();
    static ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
    static Lock read=rwl.readLock();
    static Lock write=rwl.writeLock();
    public static Object get(String key){
        read.lock(); //读锁 ThreadA 阻塞
        try{
            return cacheMap.get(key);
        }finally {
            read.unlock(); //释放读锁
        }
    }
    public static Object write(String key,Object value){
        write.lock(); //Other Thread 获得了写锁
        try{
            return cacheMap.put(key,value);
        }finally {
            write.unlock();
        }
    }
}

StampedLock

读多写少的情况下. 读和读不互斥 读和写互斥 写和写互斥

思考锁的实现(设计思维)

{互斥}
1、锁的互斥特性 -> 共享资源()-> 标记 (0 无锁, 1代表有锁)
2、没有抢占到锁的线程?-> 释放CPU资源 , [等待 -> 唤醒]
3、等待的线程怎么存储? -> 数据结构去存储一些列等待中的线程,FIFO (等待队列) 4、公平和非公平(能否插队),synchronized是一个非公平锁
5、重入的特性(识别是否是同一个人?ThreadID)
{技术方案}
1、volatile state =0 (无锁) , 1代表是持有锁 , >1代表重入
2、wait/notify | condition 无法唤醒指定线程。
而需要唤醒指定线程。[LockSupport.park(); ->unpark(thread)] unsafe类中提供的一个方法。
3、双向链表
4、逻辑层面去实现
5、在某一个地方存储当前获得锁的线程的ID,判断下次抢占锁的线程是否为同一个。

举报

相关推荐

0 条评论