线程安全访问计数器

时间:2016-03-11 05:28:31

标签: java multithreading

我正在尝试实施线程安全访问计数器。我需要做的是创建一个包含路径和整数(计数器)的HashMap。它有两种方法可以检查地图是否包含路径,如果路径出现如下所示会增加计数,如下所示

public class AccessCounter {
private HashMap<Integer,java.nio.file.Path> counter= new HashMap<Integer,java.nio.file.Path>();
private ReentrantLock lock = new ReentrantLock();  
private Path path ;
private RequestHandler rq; 

public void map(HashMap<Integer,java.nio.file.Path> counter){ 
    counter.put(10,Paths.get("/Users/a.html"));
    counter.put(5, Paths.get("b.html")); 
    counter.put(2, Paths.get("c.txt"));
    counter.put(7, Paths.get("d.txt")); 
}

public void increment(){ 
    lock.lock(); 
    System.out.println("Lock Obtained");
    try{ 
        if(counter.keySet().equals(rq.fileName())){
            for(Integer key: counter.keySet()){
                Path text = counter.get(key);   
                key++;
            }
        }
        else { 
            counter.put(1,path);
        }
    }finally{
        lock.unlock();
        System.out.println("Lock released");
    }
}

public void getCount(){ 
    lock.lock(); 
    System.out.println("Lock Obtained");
    try{ 
        if(counter.keySet().equals(rq.fileName())){
            for(Integer key: counter.keySet()){
                Path text = counter.get(key);   
                key++;
            }
        }
        else { 
            return ;
        }
    }finally{
        lock.unlock();
        System.out.println("Lock released");
    }
}

}

RequestHandler(Runnable Class) - &gt;运行() - &gt;选取其中一个文件并调用increment方法和getCount()。在main方法中,我必须同时为AccessCounter创建多个线程。谁能建议我正确的方向。我做错了什么但是找不到它。

public class RequestHandler implements Runnable {
private AccessCounter ac;
private File file;

public void select(File file) {
    File file1 = new File("a.html");
    File file2 = new File("b.html");
    File file3 = new File("a.txt");
}

public File fileName() {
    return file;
}

public void run() {
    select(file);
    ac.increment();
    ac.getCount();
}

public static void main(String[] args) {
    Thread thread1 = new Thread(new RequestHandler());
    thread1.start();
    Thread thread2 = new Thread(new RequestHandler());
    thread2.start();
}

}

2 个答案:

答案 0 :(得分:1)

  

私人HashMap计数器=新   HashMap中();

而不是HashMap<Integer,java.nio.file.Path>您需要拥有HashMap<java.nio.file.Path, Integer>,因为您的意图是拥有相同路径的条目数。

我看到了一个很好的优化,除非你想在用户代码中尝试普通HashMaplock

您可以使用上面的ConcurrentHashMap<Path, AtomicInteger>代替HashMap<..>

ConcurrentHashMap有一个putIfAbsent(...)方法,可以在一个语句中以原子方式执行它。

AtomicInteger允许我们使用incrementAndGet方法进行原子增量。

用户代码中没有额外的锁定/同步。

答案 1 :(得分:1)

使用ConcurrentHashMap和AtomicLong是线程安全性和简单性所需的全部内容。

final ConcurrentMap<Path, AtomicLong> counterMap = new ConcurrentHashMap<>();

public void incrementFor(Path path) {
    counterMap.computeIfAbsent(path, p -> new AtomicLong()).incrementAndGet();
}

public long getCount(Path path) {
    AtomicLong l = counterMap.get(path);
    return l == null ? 0 : l.get();
}

computeIfAbsent将以线程安全的方式根据需要放置一个新的AtomicLong。

注意:由于ConcurrentMap支持并发访问,您可以同时使用此Map使用多个线程(前提是它们访问不同的路径)