我正在尝试实施线程安全访问计数器。我需要做的是创建一个包含路径和整数(计数器)的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();
}
}
答案 0 :(得分:1)
私人HashMap计数器=新 HashMap中();
而不是HashMap<Integer,java.nio.file.Path>
您需要拥有HashMap<java.nio.file.Path, Integer>
,因为您的意图是拥有相同路径的条目数。
我看到了一个很好的优化,除非你想在用户代码中尝试普通HashMap
和lock
:
您可以使用上面的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使用多个线程(前提是它们访问不同的路径)