JUC----04

1.1 读写问题

ReadWriteLockUnsafeDemo:

public class ReadWriteLockUnsafeDemo {
    // TODO: 2020/7/25  模拟多线程对公共资源类的读和写操作,没有加锁,不安全
    static class Cache {
        private HashMap<String, Object> cache = new HashMap<>();

        //写入缓存
        public void put(String key, Object val) {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始写入");
                cache.put(key, val);
                System.out.println(Thread.currentThread().getName() + " 写入完成");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }

        //从缓存中读取数据
        public void get(String key) {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始读取");
                Object obj = cache.get(key);
                System.out.println(Thread.currentThread().getName() + " 读取完成 : " + obj);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
    }

    public static void main(String[] args) {
        Cache cache = new Cache();
        for (int i = 0; i < 5; ++i) {
            final int tempI = i;
            new Thread(() -> {
                cache.put(String.valueOf(tempI), tempI);
            }).start();
        }

        for (int i = 0; i < 5; ++i) {
            final int tempI = i;
            new Thread(() -> {
                cache.get(String.valueOf(tempI));
            }).start();
        }
    }
}

运行结果:

Thread-0 开始写入
Thread-1 开始写入
Thread-1 写入完成
Thread-0 写入完成
Thread-2 开始写入
Thread-2 写入完成
Thread-3 开始写入
Thread-3 写入完成
Thread-5 开始读取
Thread-5 读取完成 : 0
Thread-4 开始写入
Thread-4 写入完成
Thread-6 开始读取
Thread-6 读取完成 : 1
Thread-7 开始读取
Thread-7 读取完成 : 2
Thread-8 开始读取
Thread-9 开始读取
Thread-9 读取完成 : 4
Thread-8 读取完成 : 3

首先我们可以发现在写操作的时候线程发生的争抢。

ReadWriteLockDemo:

public class ReadWriteLockDemo {
    /**
     * * 读-读 : 无锁
     * * 读-写 : 锁
     * * 写-写 : 锁
     */
    //模拟缓存被读和被写
    static class Cache {
        private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

        private HashMap<String, Object> cache = new HashMap<>();

        //写入缓存
        public void put(String key, Object val) {
            /**
             * 加写锁
             */
            readWriteLock.writeLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 开始写入");
                cache.put(key, val);
                System.out.println(Thread.currentThread().getName() + " 写入完成");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.writeLock().unlock();
            }
        }


        //从缓存中读取数据
        public void get(String key) {
            /**
             * 加读锁
             */
            readWriteLock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 开始读取");
                Object obj = cache.get(key);
                System.out.println(Thread.currentThread().getName() + " 读取完成 : " + obj);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.readLock().unlock();
            }
        }
    }

    public static void main(String[] args) {
        Cache cache = new Cache();
        for (int i = 0; i < 5; ++i) {
          final int tempI = i;
            new Thread(() -> {
                cache.put(String.valueOf(tempI), tempI);
            }).start();
        }

        for (int i = 0; i < 5; ++i) {
            final int tempI = i;
            new Thread(() -> {
                cache.get(String.valueOf(tempI));
            }).start();
        }
    }
}

运行结果:

Thread-0 开始写入
Thread-0 写入完成
Thread-1 开始写入
Thread-1 写入完成
Thread-2 开始写入
Thread-2 写入完成
Thread-3 开始写入
Thread-3 写入完成
Thread-4 开始写入
Thread-4 写入完成
Thread-5 开始读取
Thread-5 读取完成 : 0
Thread-6 开始读取
Thread-6 读取完成 : 1
Thread-7 开始读取
Thread-7 读取完成 : 2
Thread-8 开始读取
Thread-8 读取完成 : 3
Thread-9 开始读取
Thread-9 读取完成 : 4

可以看到写操作保证了原子性,读操作不加锁任意读。
这里的读操作不加锁,可能有些人会说既然不加锁,那为什么这一步要获取读锁?

这里的加锁是为了和读操作分离开来,保证上面的读锁释放完后(读操作做完了)再进行读,而各个读线程之间是不加锁的。
java这部分东西都藏在源码里了,我个人认为上面的代码严格来说属于写优先算法。写写互斥,写优先。
熟悉操作系统的都知道读写问题一般分三种:

  • 读优先
  • 写优先
  • 读写公平
posted @ 2020-08-20 19:56  西伯利亚爱学习的狼  阅读(129)  评论(0编辑  收藏  举报