【发布时间】:2021-09-28 08:43:03
【问题描述】:
我有一个只有静态方法的类,我在代码中广泛使用了这些方法。它做一些事情(在这种情况下与文件和 URL 相关),例如:
public class FileUtilities {
private FileUtilities () {
}
public static File getDirectory(String path) {
if (path == null) {
return null;
} else {
File file = new File(path);
if (file.exists()) {
if (file.isDirectory()) {
return file;
} else {
return file.getParentFile();
}
} else {
return null;
}
}
}
}
当然这个方法只是一个例子,但是很多这些方法是不可重入的。现在我想更改我的程序以使用并行线程来提高性能,但当然使用这种代码它不会工作(例如使用ForkJoinPool 时)。
重构我的代码的最佳方法是什么(知道我希望尽可能保留静态方法,或者至少使用单例模式,因为我在代码中的很多地方都使用了这个类,而且只是实用方法,没有副作用)。
我知道我可以同步我所有的静态方法,例如:
public synchronized static File getDirectory(String path) {
但我怀疑在某些情况下会导致死锁。
我考虑过使用ThreadLocal,但我不确定在我的情况下如何使用它。我的一个想法是:
public class FileUtilities {
private static final ThreadLocal<FileUtilities> tlocal = ThreadLocal.withInitial(() -> new FileUtilities());
private FileUtilities () {
}
public static File getDirectory(String path) {
return tlocal.get().getDirectoryImpl(path);
}
private File getDirectoryImpl(String path) {
if (path == null) {
return null;
} else {
File file = new File(path);
if (file.exists()) {
if (file.isDirectory()) {
return file;
} else {
return file.getParentFile();
}
} else {
return null;
}
}
}
}
它是正确的,还是无可救药的代码?
【问题讨论】:
-
你的
getDirectory()是线程安全的,所以根本不应该碰它。应检查其他方法,并可能提出synchronized。你怎么怀疑你会陷入僵局?除了类级别的锁,您还有其他锁吗?如果在那里更有意义,您还可以在更高级别上处理并发。如果您必须询问您的ThreadLocal设计,请不要这样做。我认为您正在尝试用代码复杂性来换取假定的性能。性能需要衡量,并发代码需要仔细设计。 -
仅供参考,没有任何直接的理由来保护 方法 免受并发访问。方法访问的数据总是需要保护。如果您认为某些方法应该在访问某个变量或数据结构或对象之前锁定一个锁,那么 每个 访问同一变量/结构/对象的方法都应该锁定同一个锁。
标签: java multithreading thread-safety thread-local