一、科普定义

这篇博文的两个主角“synchronized”和“读写锁”

1)synchronized

这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用,在这就不多说只做几点归纳:

  • Java提供这个关键字,为防止资源冲突提供的内置支持。当任务执行到被synchronized保护的代码片段的时候,它检查锁是否可用,然后获取锁,执行代码,释放锁。
  • 常用这个关键字可以修饰成员方法和代码块

2)读写锁

我们对数据的操作无非两种:“读”和“写”,试想一个这样的情景,当十个线程同时读取某个数据时,这个操作应不应该加同步。答案是没必要的。只有以下两种情况需要加同步:

  • 这十个线程对这个公共数据既有读又有写
  • 这十个线程对公共数据进行写操作
  • 以上两点归结起来就一点就是有对数据进行改变的操作就需要同步

所以

java5提供了读写锁这种锁支持多线程读操作不互斥,多线程读写互斥,多线程写写互斥。读操作不互斥这样有助于性能的提高,这点在java5以前没有

二.用一道面试题来具体比较这两点

题目:“白板编程,实现一个缓存系统”
题目分析:

对这个缓存系统的理解:
间于用户和数据库中间的一个环节,我们知道用户直接访问数据库的时间是远大于直接访问内存,所以有了缓存区后用户访问数据时 这样,用户先访问缓存区当缓存区有用户需要的数据时直接拿走,当缓存区没有这样的数据,访问数据库并把访问所得的数据放在缓存区,这样当下一个需要这个数据的用户就直接访问内存即可得到。
核心代码实现:
首先用synchronized实现
1
2
3
4
5
6
7
8
public synchronized Object getData(String key){
        Object result = map.get(key);
        if(result ==null){
            result = "new";//用这步代替访问数据库得数据
        }
        return result;
 
}

用读写锁实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public Object getData(String key){
        rw.readLock().lock();//在读前先上读锁
        Object result = null;
        try{
            result = map.get(key);
                        //这个if比较关键,它避免了多余的几次对数据哭的读取
            if(result==null){
                //如果内存中没有所要数据
                rw.readLock().unlock();
                rw.writeLock().lock();
                if(result==null){
                    try{
                       //我们用这个代替对数据库访问得到数据的步骤  
                                            result = "new";
                    }finally{
                    rw.writeLock().unlock();
                    }
                    rw.readLock().lock();
                }
            }
        }finally{
            rw.readLock().unlock();
        }
        return result;
 
    }

 代码分析:

  1. 用第一种方法处理,整个过程比较粗线条,代码比较简单单执行效率很低。这种方法的中心思想是不管你是什么操作,但凡涉及到公共资源就都给你同步。这么做可以是可以但是并不好。
  2. 第二种用读写锁处理显然是对前者的一个优化,对第二种方法做如下几点说明:
  • 关于unlock操作,我们知道只要是上了锁就必须要解锁,但是有这么一种情况就是当你上完锁后在执行解锁操作前程序出现异常,那这个所可能就一直存在。所以针对这个问题我们一般将unlock操作放在finally代码块中,就可以保证上了的锁一定会被解。
  • 上面的两次if判断,第一个if相信大家很好理解。但为什么要用第二个if呢?再假设一个场景,现在有十个线程来读这个数据,而这个数据又不存在与缓存区,那么这十个线程中最先到的线程将执行“rw.writeLock().lock();”而另外九个线程将被阻塞,当第一个线程读完以后缓存区实际上已经就有了这个数据,但另外九个阻塞在“rw.writeLock().lock();”如果不加这层if他们会继续访问数据库,由此可见加了这层if对整个过程影响很大。这是比较细节的一点,就这一点Java的API文档也考虑到了,它的样例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class CachedData {
  Object data;
  volatile boolean cacheValid;
  ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
 
  void processCachedData() {
    rwl.readLock().lock();
    <span style="color: #ff0000;">if (!cacheValid)</span> {
       // Must release read lock before acquiring write lock
       rwl.readLock().unlock();
       rwl.writeLock().lock();
       // Recheck state because another thread might have acquired
       //   write lock and changed state before we did.
      <span style="color: #ff0000;"> if (!cacheValid)</span> {
         data = ...
         cacheValid = true;
       }
       // Downgrade by acquiring read lock before releasing write lock
       rwl.readLock().lock();
       rwl.writeLock().unlock(); // Unlock write, still hold read
    }
 
    use(data);
    rwl.readLock().unlock();
  }
}

比较synchronized和读写锁的更多相关文章

  1. 一道面试题比较synchronized和读写锁

    一.科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用, ...

  2. <转>一道面试题比较synchronized和读写锁

    一.科普定义(原文:http://903497571.iteye.com/blog/1874752) 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步 ...

  3. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  4. 浅谈Java中的锁:Synchronized、重入锁、读写锁

    Java开发必须要掌握的知识点就包括如何使用锁在多线程的环境下控制对资源的访问限制 ◆ Synchronized ◆ 首先我们来看一段简单的代码: 12345678910111213141516171 ...

  5. 201709020工作日记--synchronized、ReentrantLock、读写锁

    1.reentrantLock java.util.concurrent.lock 中的Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现.这就为Lock ...

  6. java多线程-读写锁

    Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...

  7. 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁

    1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...

  8. Java多线程13:读写锁和两种同步方式的对比

    读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...

  9. 利用Java的读写锁实现缓存的设计

    Java中的读写锁: 多个读锁不互斥, 读锁与写锁互斥, 写锁与写锁互斥, 这是由JVM自行控制的,我们只要上好相应的锁即可. 缓存的设计: package com.cn.gbx; import ja ...

随机推荐

  1. expand_dims

    tf.expand_dims  |  TensorFlow https://tensorflow.google.cn/api_docs/python/tf/expand_dims tf.expand_ ...

  2. 【OI】线性筛

    如何查找一个范围内的所有素数? 可以是从1~n挨个判断n%i 是否 == 0,也可以从 1~sqr(n) 一个个判断. 相信你们也听说过埃氏筛法,是使用每一个数的倍数筛掉合数!但是!每一个合数要被筛多 ...

  3. ViewPager嵌套ViewPager后子ViewPager滑动不正常问题

    ViewPager嵌套ViewPager后,滑动事件没法在子ViewPager里面响应. 解决办法是自定义子ViewPager. 以下代码是转载的,经本人测试,可以用!!! 转载地址:http://b ...

  4. 类型配置命名空间 —— XML schema

    对于基于 XML 的配置,Spring 2.0 以后告别 DTD 格式(Document Type Definition)的配置文件,开始采用 Schema 格式,Schema 的突出亮点即是可让不同 ...

  5. ATX 学习 (三)-atxserver2-android-provider

    服务端代码 代码clone到本地,搭好相应环境(怎么搭的这里就不介绍了,很好搭的哈)一般库首先查看main.py文件,debug模式开始运行 一开始就是没接触过的tornado.ioloop,有点偏底 ...

  6. Java 创建Excel并逐行写入数据

    package com.xxx.common.excel; import java.io.File; import java.io.FileInputStream; import java.io.Fi ...

  7. 创建maven项目遇到的问题

    1.新建完成的maven项目,缺少src/main/java 解决方案:把项目中的jre换成eclipse中默认的jre. 另外还可以参考:解决Eclipse建立Maven项目后无法建立src/mai ...

  8. Objective-C设计模式——中介者Mediator(对象去耦)

    中介者模式 中介者模式很好的诠释了迪米特法则,任意两个不相关的对象之间如果需要关联,那么需要通过第三个类来进行.中介者就是把一组对象进行封装,屏蔽了类之间的交互细节,使不同的类直接不需要持有对方引用也 ...

  9. leetcode692 Top K Frequent Words

    思路: 堆.实现: #include <bits/stdc++.h> using namespace std; class Solution { public: inline bool c ...

  10. input checkbox 选择内容输出多少个

    <input type="checkbox" name="qId" onclick="doit();"/><input t ...