自旋锁、乐观锁、悲观锁、重入锁、公平锁

1、乐观锁:假定没有冲突,在更新数据时比较发现不一致时,则读取新值修改后重试更新。(自旋锁就是一种乐观锁)

2、悲观锁:假定会发生冲突,所有操作都加上锁,比如读数据操作。

3、自旋锁:循环使用cup时间,尝试cas操作直至成功返回true,不然一直循环。(比较内存值与线程旧值是否一致,一致则更新,不然则循环)

4、共享锁(多读):给资源加上读锁,其他线程也可以加读锁,可以同时读,不可以加写锁。
5、独享锁(单写):给资源加上写锁,可以修改资源,其他线程不能再加锁。

6、可重入锁、不可重入锁:线程获取到一把锁后,可以自由进入同一把锁所同步的其他代码。
在这里插入图片描述

// 可重入
public class ObjectSyncDemo2 {
    
    

    public synchronized void test1(Object arg) {
    
    
        System.out.println(Thread.currentThread() + " 我开始执行 " + arg);
        if (arg == null) {
    
    
            test1(new Object());
        }
        System.out.println(Thread.currentThread() + " 我执行结束" + arg);
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        new ObjectSyncDemo2().test1(null);
    }
}
输出:
Thread[main,5,main] 我开始执行 null
Thread[main,5,main] 我开始执行 java.lang.Object@4554617c
Thread[main,5,main] 我执行结束java.lang.Object@4554617c
Thread[main,5,main] 我执行结束null

7、公平锁、非公平锁:获取锁时,按照线程先后顺序,则公平。

8、读写锁:在这里插入图片描述

// 缓存示例
public class CacheDataDemo {
    
    
    // 创建一个map用于缓存
    private Map<String, Object> map = new HashMap<>();
    private static ReadWriteLock rwl = new ReentrantReadWriteLock();

    public static void main(String[] args) {
    
    
        // 1 读取缓存里面的数据
        // cache.query()
        // 2 如果换成没数据,则取数据库里面查询  database.query()
        // 3 查询完成之后,数据塞到塞到缓存里面 cache.put(data)
    }

    public Object get(String id) {
    
    
        Object value = null;
        // 首先开启读锁,从缓存中去取
        rwl.readLock().lock();
        try {
    
    
            if (map.get(id) == null) {
    
    
                // TODO database.query();  全部查询数据库 ,缓存雪崩
                // 必须释放读锁
                rwl.readLock().unlock();
                // 如果缓存中没有释放读锁,上写锁。如果不加锁,所有请求全部去查询数据库,就崩溃了
                rwl.writeLock().lock(); // 所有线程在此处等待  1000  1  999 (在同步代码里面再次检查是否缓存)
                try {
    
    
                    // 双重检查,防止已经有线程改变了当前的值,从而出现重复处理的情况
                    if (map.get(id) == null) {
    
    
                        // TODO value = ...如果缓存没有,就去数据库里面读取
                    }
                    rwl.readLock().lock(); // 加读锁降级写锁,这样就不会有其他线程能够改这个值,保证了数据一致性
                } finally {
    
    
                    rwl.writeLock().unlock(); // 释放写锁@
                }
            }
        } finally {
    
    
            rwl.readLock().unlock();
        }
        return value;
    }
}
// 将hashmap改造一个并发安全的
// 比hashTable的实现,效率高,读取的适合并不会同步执行
public class MapDemo {
    
    
    private final Map<String, Object> m = new HashMap<>();
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();

    public Object get(String key) {
    
    
        r.lock(); // 可以同时多个线程获取这把锁
        try {
    
    
            return m.get(key);
        } finally {
    
    
            r.unlock();
        }
    }

    public Object[] allKeys() {
    
    
        r.lock();
        try {
    
    
            return m.keySet().toArray();
        } finally {
    
    
            r.unlock();
        }
    }

    public Object put(String key, Object value) {
    
    
        w.lock(); // 一个线程获取 这把锁
        try {
    
    
            return m.put(key, value);
        } finally {
    
    
            w.unlock();
        }
    }

    public void clear() {
    
    
        w.lock();
        try {
    
    
            m.clear();
        } finally {
    
    
            w.unlock();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/jue6628/article/details/109062935