简体   繁体   中英

Thread-Safe Access Counter

I am trying to implement Thread Safe Access Counter. What I need to do is create a HashMap which contains the path and integer(Counter). It has two methods which checks whether the map contains the path or not and accordingly increases the count if the path occurs as shown below

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) -> Run() -> picks up one of the files and calls increment method and getCount(). In main method I have to create multiple thread s to AccessCounter concurrently. Could anyone suggest me the right direction. I am doing something wrong but havent able to find it.

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();
}

}

private HashMap counter= new HashMap();

Instead of HashMap<Integer,java.nio.file.Path> you need to have HashMap<java.nio.file.Path, Integer> , as your intend is to have the count of number of entries with same Path.

A good optimization I see, unless you want to try with normal HashMap and lock in the user code:

You can use ConcurrentHashMap<Path, AtomicInteger> instead of HashMap<..> above.

ConcurrentHashMap has a putIfAbsent(...) method that performs it atomically in a single statement.

AtomicInteger allows us to increment atomically using incrementAndGet method.

Both without extra locks/synchronization in the user code.

Using a ConcurrentHashMap and a AtomicLong is all you need for thread safety and simplicity.

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 will place a new AtomicLong as required in a thread safe manner.

Note: as ConcurrentMap supports concurrent access, you can have many thread using this Map at the same time (provided they are accessing a different Path)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM