Java 在ExecutorService中使用同步块

Java 在ExecutorService中使用同步块,java,multithreading,deadlock,synchronized,java.util.concurrent,Java,Multithreading,Deadlock,Synchronized,Java.util.concurrent,我有以下代码片段: public class Service<T> { private ConcurrentMap<Integer, Integer> locks = new ConcurrentHashMap<Integer, Integer>(); public final ExecutorService exec = Executors.newFixedThreadPool(5); public Future<Boolea

我有以下代码片段:

public class Service<T> {
    private ConcurrentMap<Integer, Integer> locks = new ConcurrentHashMap<Integer, Integer>();
    public final ExecutorService exec = Executors.newFixedThreadPool(5);

    public Future<Boolean> foo(T o, String fileName) throws IOException {
        return exec.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws IOException {
                File f = new File(fileName);

//                synchronized (getCacheSyncObject(name.hashCode())) {
//                    try (OutputStream out = new FileOutputStream(f)) {
//                        //some actions
//                    }
//                }

                try (OutputStream out = new FileOutputStream(f)) {
                    //some actions
                }

                return true;
            }
        });
    }

    private Object getCacheSyncObject(final Integer id) {
        locks.putIfAbsent(id, id);
        return locks.get(id);
    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        Object obj = new Object();

        Service<Object> service = new Service<>();
        Future<Boolean> result1 =  service.foo(obj, "filename"); // is there a deadlock?
        service.exec.shutdown();
    }
}
公共类服务{
私有ConcurrentMap锁=新ConcurrentHashMap();
public final ExecutorService exec=Executors.newFixedThreadPool(5);
公共未来foo(to,字符串文件名)引发IOException{
return exec.submit(new Callable()){
@凌驾
公共布尔调用()引发IOException{
文件f=新文件(文件名);
//已同步(getCacheSyncObject(name.hashCode())){
//try(OutputStream out=新文件OutputStream(f)){
////一些行动
//                    }
//                }
try(OutputStream out=新文件OutputStream(f)){
//一些行动
}
返回true;
}
});
}
私有对象getCacheSyncObject(最终整数id){
锁。putIfAbsent(id,id);
返回锁。get(id);
}
}
公共班机{
公共静态void main(字符串[]args)引发IOException{
Object obj=新对象();
服务=新服务();
Future result1=service.foo(obj,“filename”);//是否存在死锁?
service.exec.shutdown();
}
}

我想完成一项简单的任务。我需要一个独占文件锁定。为了得到这个结果,我将文件名锁定到同步块。但是在这种情况下,我没有从
foo
方法中得到任何东西。我的程序没有结束。

如果您正在服务范围中查找锁,可以使用其字段存储锁。但我建议不要使用fileName.hashCode(),因为可能会发生冲突。改用全名:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class Service<T> {

    private final ConcurrentMap<String, Object> locks = new ConcurrentHashMap<>();
    public final ExecutorService exec = Executors.newFixedThreadPool(5);

    public Future<Boolean> foo(T o,
                               final String fileName) throws IOException {
        return exec.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws IOException {
                File f = new File(fileName);

                synchronized (getCacheSyncObject(fileName)) {
                    try (OutputStream out = new FileOutputStream(f)) {
                        out.write("hi".getBytes());
                    }
                }

                return true;
            }
        });
    }

    private Object getCacheSyncObject(final String name) {
        Object result = locks.get(name);

        if (result == null) {
            result = new Object();
            Object prevLock;
            if ((prevLock = locks.putIfAbsent(name, result)) != null) {
                result = prevLock;
            }
        }

        return result;
    }
}

public class Test {

    public static void main(String[] args) throws Exception {
        Object obj = new Object();

        Service<Object> service = new Service<>();
        Future<Boolean> result1 = service.foo(obj, "filename");
        service.exec.shutdown();

        System.out.println("result1 = " + result1.get());
    }
}

你不应该陷入僵局。我建议检查您的“//some actions”

程序将创建的锁数量与它在其生命周期中读取的不同文件数量大致相同。(或者,如果它运行很长时间,锁的数量将逐渐接近2^32)这可能不是您想要的。如果我要将文件映射到锁,我会有一个更小的锁池——可能是我期望在同一时间打开的文件数的一个小倍数(2倍或3倍)。你可以根据给定路径名的哈希值选择一个锁,但是可以有许多不同的路径名引用同一个文件。你说,“我需要一个独占的文件锁定。”大多数看到“文件锁定”这个词的程序员都会认为您想阻止两个或多个进程同时访问同一个文件。如果您只想同步两个或多个线程的活动,您可能想避免说“文件锁定”。
try (OutputStream out = new FileOutputStream(f)) {
    out.write("hi".getBytes());
}