Java 可运行对象中的此方法是否需要同步?
以下方法属于实现Runnable的对象A。它由来自对象A的其他方法和运行方法内部的代码异步调用(因此,它是从其他线程调用的,周期为5秒) 我最终会出现文件创建异常吗 如果我使方法同步。。。始终在对象A上获取锁? 其中一个调用者位于run()方法,这一事实让我感到困惑:S 谢谢你的意见Java 可运行对象中的此方法是否需要同步?,java,thread-safety,synchronized,Java,Thread Safety,Synchronized,以下方法属于实现Runnable的对象A。它由来自对象A的其他方法和运行方法内部的代码异步调用(因此,它是从其他线程调用的,周期为5秒) 我最终会出现文件创建异常吗 如果我使方法同步。。。始终在对象A上获取锁? 其中一个调用者位于run()方法,这一事实让我感到困惑:S 谢谢你的意见 private void saveMap(ConcurrentMap<String, String> map) { ObjectOutputStream obj = null; try
private void saveMap(ConcurrentMap<String, String> map) {
ObjectOutputStream obj = null;
try {
obj = new ObjectOutputStream(new FileOutputStream("map.txt"));
obj.writeObject(map);
} catch (IOException ex) {
Logger.getLogger(MessagesFileManager.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
obj.close();
} catch (IOException ex) {
Logger.getLogger(MessagesFileManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
notifyActionListeners();
}
private void保存映射(ConcurrentMap映射){
ObjectOutputStream obj=null;
试一试{
obj=newObjectOutputStream(newFileOutputStream(“map.txt”);
对象写入对象(映射);
}捕获(IOEX异常){
Logger.getLogger(MessagesFileManager.class.getName()).log(Level.SEVERE,null,ex);
}最后{
试一试{
obj.close();
}捕获(IOEX异常){
Logger.getLogger(MessagesFileManager.class.getName()).log(Level.SEVERE,null,ex);
}
}
notifyActionListeners();
}
同步实例方法使用此
对象作为锁,防止从不同线程同时执行所有同步实例方法(甚至其他方法)
要回答关于同步要求的问题,答案基本上是肯定的,因为有多个线程访问同一个方法,所以输出可能会冲突
作为设计注释,我将使用您的saveMap
方法static
,因为它不访问任何字段(它是无状态的),并且它更强烈地表明文件的输出不依赖于实例,因此更明显的是,文件输出可能会与其他实例发生冲突
编辑:
下面是我建议的代码:
private static synchronized void saveMap(Map<String, String> map) {
...
}
private static synchronized void保存映射(映射映射){
...
}
仅供参考,static synchronized
方法使用类对象(即MyClass.class),它是一个单例对象,作为锁对象
它由其他方法从对象A
和run
方法中的代码异步调用(因此,它是从其他线程调用的,周期为5秒)
假定从多个线程调用saveMap
,如果不进行同步,则无法保证两个线程不会同时尝试写入同一文件。发生这种情况时,将导致文件格式不正确
最简单的解决方案是使方法同步
private synchronized void saveMap(ConcurrentMap<String, String> map) { ... }
请记住,交换两个文件并不是一个原子操作。来自同一程序的任何外部程序或线程都可能捕获到
map.txt
不存在的短时间。我在Java中找不到原子文件交换方法,但也许通过一些搜索,你会找到。我不清楚你是说这个方法是从两个不同的线程调用的,还是仅仅是一个线程每5秒运行一次。如果只有一个线程运行它,那么同步该方法就没有必要,也没有用。谢谢Ryan。是的,它是从两个不同的线程调用的。一个是直接使用对象A的对象,另一个是这样创建的线程对象:Thread t=new Thread(对象A)直接使用该类,然后将其用作可运行类,这看起来很奇怪。我们看不到你在做什么,但也许你应该重新考虑你的设计。多亏了2,你的回答让我思考。该类的主要职责是从输入文件中收集数据,这是在run()方法中完成的。其他方法用于查询在run()中收集并保存在ConcurrentHashMap中的数据,并在每次添加或删除对象时使缓存数据持久化(saveMap)。因此,最好将私有静态对象mapWriteLock=new object()
作为类a的成员,然后将私有静态无效存储映射(…){synchronize(mapWriteLock){…和以前一样…}
@tototo2否-只需将方法静态同步
。请参阅编辑。非常感谢你的波西米亚风格。这是一个关于静态关键字的非常好的提示。如果一个方法是无状态的,它应该始终是静态的吗?我可以考虑提高内存效率(实例将具有更少的代码)我说得对吗?还有其他好处吗?顺便说一句,我第一次编写代码时,我确信使用ConcurrentHashMap可以确保整个过程是线程安全的,但现在我非常确定我错了。谢谢!虽然不是必需的,但无状态方法应该是静态的,作为代码读者和用户的明确信号,该方法是无状态的。我如果引入了有状态代码,t也会自动发出一个红旗-您在尝试从静态方法访问实例字段时会遇到编译器错误。此时,您可以将字段设置为静态,也可以将方法设置为非静态。无论选择什么,至少都会有意识地(因此正确地)强制执行只是为了澄清我的评论:我指的是您的“防止同时执行所有同步实例方法(甚至其他方法)”。因此,在此
上进行同步可能会降低速度,甚至是锁定此
的不相关同步方法。可能还有其他方法可以访问map.txt
,只有那些方法应该使用与saveMap
相同的锁定。
private void saveMap(ConcurrentMap<String, String> map) {
File file = ... original code to write to a temporary file ...
if (file != null) {
synchronized(this) {
... move file over map.txt ...
}
notifyActionListeners();
}
}