首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >超过ReentrantReadWriteLock readLock给出时间限制

超过ReentrantReadWriteLock readLock给出时间限制
EN

Stack Overflow用户
提问于 2021-06-27 05:51:12
回答 1查看 69关注 0票数 0

我在努力学习并发

我在玩下面的代码:

https://leetcode.com/problems/lru-cache/discuss/724784/Detailed-Explanation-with-Threadsafe-LRU-Cache-in-Java

代码语言:javascript
复制
class LRUCache {

    /**              
         Algorithm :
         
         1. Everytime when we add the node check if it exists .
            1.1 if exists then update the value .
            1.2 move this node to head.
            1.3 if the capaicity reaches then remove node from tail .
            1.4 move the current node to head.
            
         2. Everytime when we get 
            2.1 then we need to move this node to head.
            
         3. Remove the node from tail thats it.   
          
       }
    **/
    
    private int  capacity;
    private AtomicInteger  curSize = new AtomicInteger() ;
    private ConcurrentHashMap<Integer,Node> map = new ConcurrentHashMap<>();
    private Node head = new Node();
    private Node tail = new Node();
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        if(!map.containsKey(key))
             return -1;
        Node node = map.get(key);
        // move this current Node to front
        moveToHead(node);
        return node.val;
        
    }
    
    public void put(int key, int value) {
        // The key is already present 
        Node curNode = map.get(key);
        if(curNode != null){
           // if value exist update
            curNode.val=value;
           // moveTo head , so now its used recently 
           moveToHead(curNode);
           return;
        }
        Node newNode = new Node(value,key);
        map.put(key,newNode);
        addToHead(newNode);
        if( curSize.incrementAndGet() > capacity){
            Node nodeToRemove = tail.prev;
            removeNode(nodeToRemove);
            map.remove(nodeToRemove.key);
            curSize.decrementAndGet();
        }
    }
    
    private void moveToHead(Node node){
        // remove 
        removeNode(node);
        addToHead(node);
        
    }
    
    private void removeNode(Node node){
        try{
            readWriteLock.writeLock().lock();
            Node prev = node.prev;
            Node next = node.next;
            prev.next = next;
            next.prev = prev;
        }finally{
            readWriteLock.writeLock().unlock();
        }
    }
    
    private void addToHead(Node node){
        try{
            readWriteLock.writeLock().lock();
            node.next = head.next;
            node.prev = head;
            head.next.prev = node;
            head.next = node;
        }finally{
            readWriteLock.writeLock().unlock();
        }
    }
}

class Node {
   Integer val;
   Integer key; 
   Node next ;
   Node prev;
    
   public Node(int val, int key){
         this.val = val;
         this.key = key;
    } 
    
   public Node(){
       
   } 
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

我观察到get方法没有任何线程安全,所以我就这样修改了它。

代码语言:javascript
复制
    public int get(int key) {
     readWriteLock.readLock().lock();

   try{
        if(!map.containsKey(key))
             return -1;
        Node node = map.get(key);
        // move this current Node to front
        moveToHead(node);
        return node.val;
       
         }finally{
            readWriteLock.readLock().unlock();
        }   
        
    }

我认为这将确保,reads不会在writes运行时发生。

但是在修改get函数之后,在Leetcode中我得到了超过时间限制的信息。谁能解释一下原因吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-27 08:16:24

我在努力学习并发 我在玩下面的代码:

我强烈建议您不要从这段代码中学习并发性,因为它充满了各种并发错误。

从这种天真的错误中:

代码语言:javascript
复制
        if(!map.containsKey(key))
             return -1;
        Node node = map.get(key);
        // move this current Node to front
        moveToHead(node);
        return node.val;

containsKey之后和get之前,另一个线程可能会删除密钥,因此,我们将得到node==nullNullPointerExcetion

对于更多特定于java的错误,如以下所示:

代码语言:javascript
复制
curNode.val=value;

在这里,新值被写到val而没有适当的同步,这就创建了一个所谓的数据竞争(即在其他线程中读取val将返回奇怪的结果)。

修复代码的最简单方法是使每个公共方法都是synchronized,并丢弃readWriteLock

同样,在这种情况下,将AtomicIntegerConcurrentHashMap替换为intHashMap是合理的(您不需要使用synchronized的并发版本)。

如果您想在java中学习并发性,那么我建议:

  1. Java并发在实践中的应用 --这是一本由java作者撰写的书,它给出了用java编写并发代码的简单实用规则。(不幸的是,IMHO还不够深入)
  2. 要学习Java模型,它是一个Java语言规范的一部分,它定义了当多个java线程访问内存中的相同数据时会发生什么。 至少在规则制定之前就知道发生了什么是至关重要的。 不幸的是,我不知道任何关于这方面的简单明了的书籍/文章。
  3. 多处理器编程艺术学习各种无锁和无等待算法(对于这些算法来说,像AtomicInteger这样的东西是真正存在的)。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68148385

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档