??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品97,亚洲激情国产,亚洲一区二区久久久久久http://blogjava.net/DLevin/category/49040.htmlIn general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatrazh-cnThu, 13 Aug 2015 10:48:08 GMTThu, 13 Aug 2015 10:48:08 GMT60实现自己的Lock对象http://www.aygfsteel.com/DLevin/archive/2015/08/11/426723.htmlDLevinDLevinMon, 10 Aug 2015 22:08:00 GMThttp://www.aygfsteel.com/DLevin/archive/2015/08/11/426723.htmlhttp://www.aygfsteel.com/DLevin/comments/426723.htmlhttp://www.aygfsteel.com/DLevin/archive/2015/08/11/426723.html#Feedback0http://www.aygfsteel.com/DLevin/comments/commentRss/426723.htmlhttp://www.aygfsteel.com/DLevin/services/trackbacks/426723.html一直想好好学习concurrent包中的各个类的实玎ͼ然而经常看了一点就因ؓ其他事情q扰而放下了。发现这样太不利于自q成长了,因而最q打潜心一件一件的完成自己惛_习的东西?br />
对concurrent包的学习打算先从Lock的实现开始,因而自然而然的就端v了AbstractQueuedSynchronizerQ然而要Lq个cȝ源码q不是那么容易,因而我开始问自己一个问题:如果自己要去实现q个一个Lock对象Q应该如何实现呢Q?br />
要实现Lock对象Q首先理解什么是锁?我自׃~程角度单的理解Q所谓锁对象Q互斥锁Q就是它能保证一ơ只有一个线E能q入它保护的临界区,如果有一个线E已l拿到锁对象Q那么其他对象必让权等待,而在该线E退个界区旉要唤醒等待列表中的其他线E。更学术一些,《计机操作pȝ?/a>中对同步机制准则的归UIP50Q:

  1. I闲让进。当无进E处于界区Ӟ表明临界资源处于I闲状态,应允怸个请求进入界区的进E立卌入自q临界区,以有效的利用临界资源?/li>
  2. 忙则{待。当已有q程q入临界区时Q表明界资源正在被讉KQ因而其他试图进入界区的进E必ȝ待,以保证对临界源的互斥讉K?/li>
  3. 有限{待。对要求讉K临界资源的进E,应保证在有限旉内能q入自己的界区Q以免陷?#8220;ȝ”状态?/li>
  4. 让权{待。当q程不能q入自己的界区Ӟ应该释放处理机,以免q程陷入“忙等”状态?/li>

说了那么多,其实对互斥锁很简单,只需要一个标CQ如果该标记位ؓ0Q表C没有被占用Q因而直接获得锁Q然后把该标C|ؓ1Q此时其他线E发现该标记位已l是1Q因而需要等待。这里对q个标记位的比较q设值必L原子操作Q而在JDK5以后提供的atomic包里的工L可以很方便的提供q个原子操作。然而上面的四个准则应该漏了一点,即释N的线E(q程Q和得到锁的U程Q进E)应该是同一个,像一把钥匙对应一把锁Q理想的Q,所以一个非常简单的Lockcd以这么实玎ͼ

public class SpinLockV1 {
    
private final AtomicInteger state = new AtomicInteger(0);
    
private volatile Thread owner; // q里owner字段可能存在中间|不可靠,因而其他线E不可以依赖q个字段的?/span>
    
    
public void lock() {
        
while (!state.compareAndSet(01)) { }
        owner 
= Thread.currentThread();
    }
    
    
public void unlock() {
        Thread currentThread 
= Thread.currentThread();
        
if (owner != currentThread || !state.compareAndSet(10)) {
            
throw new IllegalStateException("The lock is not owned by thread: " + currentThread);
        }
        owner 
= null;
    }
}

一个简单的试ҎQ?br />

    @Test
    
public void testLockCorrectly() throws InterruptedException {
        
final int COUNT = 100;
        Thread[] threads 
= new Thread[COUNT];
        SpinLockV1 lock 
= new SpinLockV1();
        AddRunner runner 
= new AddRunner(lock);
        
for (int i = 0; i < COUNT; i++) { 
            threads[i] 
= new Thread(runner, "thread-" + i);
            threads[i].start();
        }
        
        
for (int i = 0; i < COUNT; i++) {
            threads[i].join();
        }
        
        assertEquals(COUNT, runner.getState());
    }
    
    
private static class AddRunner implements Runnable {
        
private final SpinLockV1 lock;
        
private int state = 0;

        
public AddRunner(SpinLockV1 lock) {
            
this.lock = lock;
        }
        
        
public void run() {
            lock.lock();
            
try {
                quietSleep(
10);
                state
++;
                System.out.println(Thread.currentThread().getName() 
+ "" + state);
            } 
finally {
                lock.unlock();
            }
        }
        
        
public int getState() {
            
return state;
        }
    }

然而这个SpinLock其实q不需要stateq个字段Q因为owner的赋g否也是一U状态,因而可以用它作ZU互斥状态:

public class SpinLockV2 {
    
private final AtomicReference<Thread> owner = new AtomicReference<Thread>(null);
    
    
public void lock() {
        
final Thread currentThread = Thread.currentThread();
        
while (!owner.compareAndSet(null, currentThread)) { }
    }
    
    
public void unlock() {
        Thread currentThread 
= Thread.currentThread();
        
if (!owner.compareAndSet(currentThread, null)) {
            
throw new IllegalStateException("The lock is not owned by thread: " + currentThread);
        }
    }
}

q在操作pȝ中被定义为整形信号量Q然而整形信号量如果没拿到锁会一直处?#8220;忙等”状态(没有遵@有限{待和让权等待的准则Q,因而这U锁也叫Spin LockQ在短暂的等待中它可以提升性能Q因为可以减线E的切换Qconcurrent包中的Atomic大部分都采用q种机制实现Q然而如果需要长旉的等待,“忙等”会占用不必要的CPU旉Q从而性能会变的很差,q个时候就需要将没有拿到锁的U程攑ֈ{待列表中,q种方式在操作系l中也叫记录型信号量Q它遵@了让权等待准则(当前没有实现有限{待准则Q。在JDK6以后提供了LockSupport.park()/LockSupport.unpark()操作Q可以将当前U程攑օ一个等待列表或一个线E从q个{待列表中唤醒。然而这个park/unpark的等待列表是一个全局的等待列表,在unpartk的时候还是需要提供需要唤醒的Thread对象Q因而我们需要维护自q{待列表Q但是如果我们可以用JDK提供的工LConcurrentLinkedQueueQ就非常Ҏ实现Q如LockSupport文档中给出来?a >代码事例Q?br />

class FIFOMutex {
   
private final AtomicBoolean locked = new AtomicBoolean(false);
   
private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();

   
public void lock() {
     
boolean wasInterrupted = false;
     Thread current 
= Thread.currentThread();
     waiters.add(current);

     
// Block while not first in queue or cannot acquire lock
     while (waiters.peek() != current || !locked.compareAndSet(falsetrue)) {
        LockSupport.park(
this);
        
if (Thread.interrupted()) // ignore interrupts while waiting
          wasInterrupted = true;
     }

     waiters.remove();
     
if (wasInterrupted)          // reassert interrupt status on exit
        current.interrupt();
   }

   
public void unlock() {
     locked.set(
false);
     LockSupport.unpark(waiters.peek());
   }
 }

在该代码事例中,有一个线E等待队列和锁标记字D,每次调用lock时先当前线E放入这个等待队列中Q然后拿出队列头U程对象Q如果该U程对象正好是当前线E,q且成功 使用CAS方式讄locked字段Q这里需要两个同时满I因ؓ可能出现一个线E已l从队列中移除了但还没有unlockQ此时另一个线E调用lockҎQ此旉列头的线E就是第二个U程Q然而由于第一个线E还没有unlock或者正在unlockQ因而需要用CAS原子操作来判断是否要parkQ,表示该线E竞争成功,获得锁,否则当前线EparkQ这里之所以要攑֜ while循环中,因ؓpark操作可能无理p?spuriously)Q如文档中给出的描述Q?br />

LockSupport.park()
public static void park(Object blocker)
Disables the current thread for thread scheduling purposes unless the permit is available.

If the permit is available then it is consumed and the call returns immediately; otherwise the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happens:

  • Some other thread invokes unpark with the current thread as the target; or
  • Some other thread interrupts the current thread; or
  • The call spuriously (that is, for no reason) returns.

This method does not report which of these caused the method to return. Callers should re-check the conditions which caused the thread to park in the first place. Callers may also determine, for example, the interrupt status of the thread upon return.

Parameters:
blocker - the synchronization object responsible for this thread parking
Since:
1.6
我在实现自己的类时就被这?#8220;无理p?#8221;坑了好久。对于已l获得锁的线E,该U程从等待队列中U除Q这里由于ConcurrentLinkedQueue是线E安全的Q因而能保证每次都是队列头的U程得到锁,因而在得到锁匙队列头U除。unlock逻辑比较单,只需要将locked字段打开Q设|ؓfalseQ,唤醒QunparkQ队列头的线E即可,然后该线E会l箋在lockҎ的while循环中l竞争unlocked字段Qƈ它自己从线E队列中U除表示获得锁成功。当然安全v见,最好在unlock中加入一些验证逻辑Q如解锁的线E和加锁的线E需要相同?br />
然而本文的目的是自己实C个Lock对象Q即只用一些基本的操作Q而不使用JDK提供的AtomiccdConcurrentLinkedQueue。类似的首先我们也需要一个队列存攄待线E队列(公^赯Q用先q先出队列)Q因而先定义一个Node对象用以构成q个队列Q?br />

 

    protected static class Node {
        
volatile Thread owner;
        
volatile Node prev;
        
volatile Node next;
        
        
public Node(Thread owner) {
            
this.owner = owner;
            
this.state = INIT;
        }
        
        
public Node() {
            
this(Thread.currentThread());
        }
    }

单v见,队列头是一个v点的placeholderQ每个调用lock的线E都先将自己竞争攑օq个队列,每个队列头后一个线E(NodeQ即是获得锁的线E,所以我们需要有head Node字段用以快速获取队列头的后一个NodeQ而tail Node字段用来快速插入新的NodeQ所以关键在于如何线E安全的构徏q个队列Q方法还是一LQ用CAS操作Q即CASҎ自p|成tail|然后重新构徏q个列表Q?br />

    protected boolean enqueue(Node node) {
        
while (true) {
            
final Node preTail = tail;
            node.prev 
= preTail;
            
if (compareAndSetTail(preTail, node)) {
                preTail.next 
= node;
                
return node.prev == head;
            }
        }
    }

在当前线ENode以线E安全的方式攑օq个队列后,lock实现相对比较简单了Q如果当前Node是的前驱是headQ该U程获得锁,否则park当前U程Q处理park无理p回的问题Q因而将park攑օwhile循环中(该实现是一个不可重入的实现Q:

    public void lock() {
        
// Put the latest node to a queue first, then check if the it is the first node
        
// this way, the list is the only shared resource to deal with
        Node node = new Node();
        
if (enqueue(node)) {
            current 
= node.owner;
        } 
else {
            
while (node.prev != head) {
                LockSupport.park(
this); // This may return "spuriously"!!, so put it to while
            }

            current 
= node.owner;
        }
    }

unlock的实现需要考虑多种情况Q如果当前Node(head.next)有后驱,那么直接unpark该后驱即可;如果没有Q表C当前已l没有其他线E在{待队列中,然而在q个判断q程中可能会有其他线E进入,因而需要用CAS的方式设|tailQ如果设|失败,表示此时有其他线E进入,因而需要将该新q入的线Eunpark从而该新进入的U程在调用park后可以立卌回(q里的CAS和enqueue的CAS都是对tail操作Q因而能保证状态一_Q?br />

    public void unlock() {
        Node curNode 
= unlockValidate();
        Node next 
= curNode.next;
        
if (next != null) {
           
head.next = next;
            next.prev 
= head;
            LockSupport.unpark(next.owner);
        } 
else {
            
if (!compareAndSetTail(curNode, head)) {
               
while (curNode.next == null) { } // Wait until the next available
                // Another node queued during the time, so we have to unlock that, or else, this node can never unparked
                unlock();
            } 
else {
               
compareAndSetNext(head, curNode, null); // Still use CAS here as the head.next may already been changed
            }
        }
    }

具体的代码和试cd以参考查?a >q里?br />


其实直到自己写完q个cd才直到者其实这是一个MCS锁的变种Q因而这个实现每个线Epark在自w对应的node上,而由前一个线Eunpark它;而AbstractQueuedSynchronizer是CLH锁,因ؓ它的park由前q态决定,虽然它也是由前一个线Eunpark它。具体可以参?a >q里?/p>

DLevin 2015-08-11 06:08 发表评论
]]>
ReferenceCountSet无锁实现http://www.aygfsteel.com/DLevin/archive/2014/12/06/421110.htmlDLevinDLevinFri, 05 Dec 2014 16:29:00 GMThttp://www.aygfsteel.com/DLevin/archive/2014/12/06/421110.htmlhttp://www.aygfsteel.com/DLevin/comments/421110.htmlhttp://www.aygfsteel.com/DLevin/archive/2014/12/06/421110.html#Feedback3http://www.aygfsteel.com/DLevin/comments/commentRss/421110.htmlhttp://www.aygfsteel.com/DLevin/services/trackbacks/421110.html阅读全文

DLevin 2014-12-06 00:29 发表评论
]]>
Java Cachepd之Cache概述和Simple Cachehttp://www.aygfsteel.com/DLevin/archive/2013/10/15/404770.htmlDLevinDLevinTue, 15 Oct 2013 15:46:00 GMThttp://www.aygfsteel.com/DLevin/archive/2013/10/15/404770.htmlhttp://www.aygfsteel.com/DLevin/comments/404770.htmlhttp://www.aygfsteel.com/DLevin/archive/2013/10/15/404770.html#Feedback1http://www.aygfsteel.com/DLevin/comments/commentRss/404770.htmlhttp://www.aygfsteel.com/DLevin/services/trackbacks/404770.html
记得我最早接触Cache是在大学学计机l成原理的时候,׃CPU的速度要远大于内存的读取速度Qؓ了提高CPU的效率,CPU会在内部提供~存区,该缓存区的读取速度和CPU的处理速度cMQCPU可以直接从缓存区中读取数据,从而解决CPU的处理速度和内存读取速度不匹配的问题。缓存之所以能解决q个问题是基于程序的局部性原理,?#8221;E序在执行时呈现出局部性规律,卛_一D|间内Q整个程序的执行仅限于程序中的某一部分。相应地Q执行所讉K的存储空间也局限于某个内存区域。局部性原理又表现为:旉局部性和I间局部性。时间局部性是指如果程序中的某条指令一旦执行,则不久之后该指o可能再次被执行;如果某数据被讉KQ则不久之后该数据可能再ơ被讉K。空间局部性是指一旦程序访问了某个存储单元Q则不久之后。其附近的存储单元也被讉K?#8221;在实际工作中QCPU先向~存取数据,如果~存区已存在Q则d~存中的数据Q命中)Q否则(失效Q,内存中相应数据块蝲入缓存中Q以提高接下来的讉K速度。由于成本和CPU大小的限ӞCPU只能提供有限的缓存区Q因而缓存区的大是衡量CPU性能的重要指标之一?br />
使用~存Q在CPU向内存更新数据时需要处理一个问题(写回{略问题Q,即CPU在更新数据时只更新缓存的数据Qwrite backQ写回,当缓存需要被替换时才缓存中更新的值写回内存)Q还是CPU在更新数据时同时更新~存中和内存中的数据Qwrite throughQ写通)。在写回{略中,Z减少内存写操作,~存块通常q设有一个脏位(dirty bitQ,用以标识该块在被载入之后是否发生q更新。如果一个缓存块在被|换回内存之前从未被写入q,则可以免d写操作;写回的优Ҏ节省了大量的写操作。这主要是因为,对一个数据块内不同单元的更新仅需一ơ写操作卛_完成。这U内存带宽上的节省进一步降低了能耗,因此颇适用于嵌入式pȝ。写通策略由于要l常和内存交互(有些CPU设计会在中间提供写缓冲器以缓解性能Q,因而性能较差Q但是它实现单,而且能简单的l持数据一致性?br />
在Y件的~存pȝ中,一般是Z解决内存的访问速率和磁盘、网l、数据库Q属于磁盘或|络讉KQ单独列出来因ؓ它的应用比较q泛Q等讉K速率不匹配的问题Q对于内存缓存系l来_。但是由于内存大和成本的限Ӟ我们又不能把所有的数据先加载进内存来。因而如CPU中的~存Q我们只能先一部分数据保存在缓存中。此Ӟ对于~存Q我们一般要解决如下需求:
  1. 使用l定Key从Cache中读取Value倹{CPU是通过内存地址来定位内存已获取相应内存中的|cM的在软gCache中,需要通过某个Key值来标识相关的倹{因而可以简单的认ؓ软g中的Cache是一个存储键值对的MapQ比如Gemfire中的Regionq承自MapQ只是Cache的实现更加复杂?/li>
  2. 当给定的Key在当前Cache不存在时Q程序员可以通过指定相应的逻辑从其他源Q如数据库、网l等源)中加载该Key对应的Value|同时该D回。在CPU中,ZE序局部性原理,一般是默认的加载接下来的一D内存块Q然而在软g中,不同的需求有不同的加载逻辑Q因而需要用戯己指定对应的加蝲逻辑Q而且一般来说也很难预知接下来要d的数据,所以只能一ơ只加蝲一条纪录(对可预知的场景下当然可以扚w加蝲数据Q只是此旉要权衡当前操作的响应旉问题Q?/li>
  3. 可以向Cache中写入KeyQValue键值对Q新增的U录或对原有的键值对的更斎ͼ。就像CPU的写回策略中有写回和写通策略,有些Cachepȝ提供了写通接口。如果没有提供写通接口,E序员需要额外的逻辑处理写通策略。也可以如CPU中的Cache一P只当相应的键值对UdCache以后Q再值写回到数据源,可以提供一个标C以决定要不要写回Q不q感觉这U实现比较复杂,代码的的耦合度也比较高,如果为提升写的速度Q采用异步写回即可,为防止数据丢失,可以使用Queue来存储)?/li>
  4. 给定Key的键值对UdCacheQ或l定多个Key以批量移除,甚至清除整个CacheQ?/li>
  5. 配置Cache的最大用率Q当Cache过该用率Ӟ可配|溢出策?
    1. 直接U除溢出的键值对。在U除时决定是否要写回已更新的数据到数据源?/li>
    2. 溢出的溢出的键值对写到盘中。在写磁盘时需要解军_何序列化键值对Q如何存储序列化后的数据到磁盘中Q如何布局盘存储Q如何解决磁盘碎片问题,如何从磁盘中扑֛相应的键值对Q如何读取磁盘中的数据ƈ方序列化Q如何处理磁盘溢出等问题?/li>
    3. 在溢出策略中Q除了如何处理溢出的键值对问题Q还需要处理如何选择溢出的键值对问题。这有点cM内存的页面置换算法(其实内存也可以看作是对磁盘的CacheQ,一般用的法有:先进先出QFIFOQ、最q最用(LRUQ、最用(LFUQ、Clock|换Q类LRUQ、工作集{算法?/li>
  6. 对Cache中的键值对Q可以配|其生存旉Q以处理某些键值对在长旉不被使用Q但是又没能溢出的问题(因ؓ溢出{略的选择或者Cache没有到溢出阶D)Q以提前释放内存?/li>
  7. Ҏ些特定的键值对Q我们希望它能一直留在内存中不被溢出Q有些Cachepȝ提供PIN配置Q动态或静态)Q以保该键值对不会被溢出?/li>
  8. 提供Cache状态、命中率{统计信息,如磁盘大、Cache大小、^均查询时间、每U查询次数、内存命中次数、磁盘命中次数等信息?/li>
  9. 提供注册Cache相关的事件处理器Q如Cache的创建、Cache的销毁、一条键值对的添加、一条键值对的更新、键值对溢出{事件?/li>
  10. ׃引入Cache的目的就是ؓ了提升程序的d性能Q而且一般Cache都需要在多线E环境下工作Q因而在实现时一般需要保证线E安全,以及提供高效的读写性能?/li>
在Java中,Map是最单的CacheQؓ了高效的在多U程环境中用,可以使用ConcurrentHashMapQ这也正是我之前参与的一个项目中最开始的实现Q后来引入EHCacheQ。ؓ了语意更加清晰、保持接口的单,下面我实C一个基于Map的最单的CachepȝQ用以演CCache的基本用方式。用户可以向它提供数据、查询数据、判断给定Key的存在性、移除给定的Key(s)、清除整个Cache{操作。以下是Cache的接口定义?br />
public interface Cache<K, V> {
    public String getName();
    public V get(K key);
    public Map<? extends K, ? extends V> getAll(Iterator<? extends K> keys);
    public boolean isPresent(K key);
    public void put(K key, V value);
    public void putAll(Map<? extends K, ? extends V> entries);
    public void invalidate(K key);
    public void invalidateAll(Iterator<? extends K> keys);
    public void invalidateAll();
    public boolean isEmpty();
    public int size();
    public void clear();
    public Map<? extends K, ? extends V> asMap();
}
q个单的Cache实现只是对HashMap的封装,之所以选择HashMap而不是ConcurrentHashMap是因为在ConcurrentHashMap无法实现getAll()ҎQƈ且这里所有的操作我都加锁了,因而也不需要ConcurrentHashMap来保证线E安全问题;Z提升性能Q我使用了读写锁Q以提升q发查询性能。因Z码比较简单,所以把所有代码都贴上了(懒得整理了。。。。)?br />
public class CacheImpl<K, V> implements Cache<K, V> {
    private final String name;
    private final HashMap<K, V> cache;
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();
    
    public CacheImpl(String name) {
        this.name = name;
        cache = new HashMap<K, V>();
    }
    
    public CacheImpl(String name, int initialCapacity) {
        this.name = name;
        cache = new HashMap<K, V>(initialCapacity);
    }
    
    public String getName() {
        return name;
    }

    public V get(K key) {
        readLock.lock();
        try {
            return cache.get(key);
        } finally {
            readLock.unlock();
        }
    }

    public Map<? extends K, ? extends V> getAll(Iterator<? extends K> keys) {
        readLock.lock();
        try {
            Map<K, V> map = new HashMap<K, V>();
            List<K> noEntryKeys = new ArrayList<K>();
            while(keys.hasNext()) {
                K key = keys.next();
                if(isPresent(key)) {
                    map.put(key, cache.get(key));
                } else {
                    noEntryKeys.add(key);
                }
            }
            
            if(!noEntryKeys.isEmpty()) {
                throw new CacheEntriesNotExistException(this, noEntryKeys);
            }
            
            return map;
        } finally {
            readLock.unlock();
        }
    }

    public boolean isPresent(K key) {
        readLock.lock();
        try {
            return cache.containsKey(key);
        } finally {
            readLock.unlock();
        }
    }

    public void put(K key, V value) {
        writeLock.lock();
        try {
            cache.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }

    public void putAll(Map<? extends K, ? extends V> entries) {
        writeLock.lock();
        try {
            cache.putAll(entries);
        } finally {
            writeLock.unlock();
        }
    }

    public void invalidate(K key) {
        writeLock.lock();
        try {
            if(!isPresent(key)) {
                throw new CacheEntryNotExistsException(this, key);
            }
            cache.remove(key);
        } finally {
            writeLock.unlock();
        }
    }

    public void invalidateAll(Iterator<? extends K> keys) {
        writeLock.lock();
        try {
            List<K> noEntryKeys = new ArrayList<K>();
            while(keys.hasNext()) {
                K key = keys.next();
                if(!isPresent(key)) {
                    noEntryKeys.add(key);
                }
            }
            if(!noEntryKeys.isEmpty()) {
                throw new CacheEntriesNotExistException(this, noEntryKeys);
            }
            
            while(keys.hasNext()) {
                K key = keys.next();
                invalidate(key);
            }
        } finally {
            writeLock.unlock();
        }
    }

    public void invalidateAll() {
        writeLock.lock();
        try {
            cache.clear();
        } finally {
            writeLock.unlock();
        }
    }

    public int size() {
        readLock.lock();
        try {
            return cache.size();
        } finally {
            readLock.unlock();
        }
    }

    public void clear() {
        writeLock.lock();
        try {
            cache.clear();
        } finally {
            writeLock.unlock();
        }
    }

    public Map<? extends K, ? extends V> asMap() {
        readLock.lock();
        try {
            return new ConcurrentHashMap<K, V>(cache);
        } finally {
            readLock.unlock();
        }
    }

    public boolean isEmpty() {
        readLock.lock();
        try {
            return cache.isEmpty();
        } finally {
            readLock.unlock();
        }
    }

}
其简单的使用用例如下Q?
    @Test
    public void testCacheSimpleUsage() {
        Book uml = bookFactory.createUMLDistilled();
        Book derivatives = bookFactory.createDerivatives();
        
        String umlBookISBN = uml.getIsbn();
        String derivativesBookISBN = derivatives.getIsbn();
        
        Cache<String, Book> cache = cacheFactory.create("book-cache");
        cache.put(umlBookISBN, uml);
        cache.put(derivativesBookISBN, derivatives);
        
        Book fetchedBackUml = cache.get(umlBookISBN);
        System.out.println(fetchedBackUml);
        
        Book fetchedBackDerivatives = cache.get(derivativesBookISBN);
        System.out.println(fetchedBackDerivatives);
    }


DLevin 2013-10-15 23:46 发表评论
]]>
Map deserialize from Stringhttp://www.aygfsteel.com/DLevin/archive/2011/09/20/359078.htmlDLevinDLevinTue, 20 Sep 2011 07:54:00 GMThttp://www.aygfsteel.com/DLevin/archive/2011/09/20/359078.htmlhttp://www.aygfsteel.com/DLevin/comments/359078.htmlhttp://www.aygfsteel.com/DLevin/archive/2011/09/20/359078.html#Feedback0http://www.aygfsteel.com/DLevin/comments/commentRss/359078.htmlhttp://www.aygfsteel.com/DLevin/services/trackbacks/359078.html 1public class MapDeserialize {
 2    public static void main(String[] args) {
 3        Map<String, String> map = new HashMap<String, String>();
 4        map.put("key1""value1");
 5        map.put("key2"null);
 6        map.put("key3""");
 7        
 8        System.out.println(map);
 9        
10        Map<String, String> emptyMap = new HashMap<String, String>();
11        System.out.println(emptyMap);
12        
13        MapDeserialize deserialize = new MapDeserialize();
14        String str1 = "{key3=, key2=null, key1=value1}";
15        String str2 = "{}";
16        Map<String, String> map1 = deserialize.str2Map(str1);
17        System.out.println("map1: " + map1);
18        Map<String, String> map2 = deserialize.str2Map(str2);
19        System.out.println("map2: " + map2);
20    }

21    
22    // We are assuming that the str is generated by map.toString(), so the str will be something like:
23    // '{key3=, key2=null, key1=value1}' or '{}'
24    public Map<String, String> str2Map(String str) {
25        Map<String, String> map = new HashMap<String, String>();
26        // The parameters map is empty
27        if("{}".equals(str) || str == null || str.length() == 0{
28            return map;
29        }

30        
31        // Remove the '{' prefix and '}' suffix
32        str = str.substring(1, str.length() - 1);
33        String[] entries = str.split(",");
34        for(String entry : entries) {
35            String[] pair = entry.split("=");
36            String key = pair[0].trim();
37            if(pair.length == 1{
38                map.put(key, "");
39            }
 else {
40                String value = pair[1].trim();
41                if("null".equals(value)) {
42                    map.put(key, null);
43                }
 else {
44                    map.put(key, value);
45                }

46            }

47        }

48        
49        return map;
50    }

51}
q段代码貌似没什么h|只是保留着Q以后再遇到相应的情况,可以再做改进?

DLevin 2011-09-20 15:54 发表评论
]]>
StopWatchc?/title><link>http://www.aygfsteel.com/DLevin/archive/2011/07/08/353922.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Fri, 08 Jul 2011 03:05:00 GMT</pubDate><guid>http://www.aygfsteel.com/DLevin/archive/2011/07/08/353922.html</guid><wfw:comment>http://www.aygfsteel.com/DLevin/comments/353922.html</wfw:comment><comments>http://www.aygfsteel.com/DLevin/archive/2011/07/08/353922.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/DLevin/comments/commentRss/353922.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/DLevin/services/trackbacks/353922.html</trackback:ping><description><![CDATA[     摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->  1/** *//**  2 * 在C#中提供了一个专门用于简单测试运行时间的cStopWatchQ?nbsp; 3&nb...  <a href='http://www.aygfsteel.com/DLevin/archive/2011/07/08/353922.html'>阅读全文</a><img src ="http://www.aygfsteel.com/DLevin/aggbug/353922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/DLevin/" target="_blank">DLevin</a> 2011-07-08 11:05 <a href="http://www.aygfsteel.com/DLevin/archive/2011/07/08/353922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">̩</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʤ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¡</a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">®</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ͨ</a>| <a href="http://" target="_blank">ҽ</a>| <a href="http://" target="_blank">ո</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽʡ</a>| <a href="http://" target="_blank">ͼƬ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ൺ</a>| <a href="http://" target="_blank">˳ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Է</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ī</a>| <a href="http://" target="_blank">ʡ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ڻ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¤</a>| <a href="http://" target="_blank">Ǩ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank">Ǽ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>