双从检查

1、科普定义java

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

1)synchronized数据库

这个同步关键字相信你们都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用,在这就很少说只作几点概括:编程

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

2)读写锁缓存

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

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

因此性能

java5提供了读写锁这种锁支持多线程读操做不互斥,多线程读写互斥,多线程写写互斥。读操做不互斥这样有助于性能的提升,这点在java5之前没有优化

 

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

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

题目分析:

 

对这个缓存系统的理解:

间于用户和数据库中间的一个环节,咱们知道用户直接访问数据库的时间是远大于直接访问内存,因此有了缓存区后用户访问数据时 这样,用户先访问缓存区当缓存区有用户须要的数据时直接拿走,当缓存区没有这样的数据,访问数据库并把访问所得的数据放在缓存区,这样当下一个须要这个数据的用户就直接访问内存便可获得。

核心代码实现:

首先用synchronized实现

public synchronized Object getData(String key){
        Object result = map.get(key);
        if(result ==null){
            result = "new";//用这步代替访问数据库得数据
        }
        return result;
 
}

用读写锁实现

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文档也考虑到了,它的样例代码以下:
  • 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();
      }
    }
相关文章
相关标签/搜索