在 Java 中使用异步线程编辑文件
Posted
技术标签:
【中文标题】在 Java 中使用异步线程编辑文件【英文标题】:Editing a file using async threads in Java 【发布时间】:2021-11-11 07:30:24 【问题描述】:我是一名小型 Java 开发人员,目前正在开发一个我用 Java 制作的不和谐机器人。我的机器人的功能之一是只要有人发送消息(以及其他条件,但这与我遇到的问题无关),就可以简单地拥有一个调平系统。
每当有人发送消息时,都会触发一个事件并创建一个线程来计算用户应该获得多少 exp。最终调用了编辑存储文件的函数。
在稀疏调用时效果很好。但是如果两个线程尝试一次写入文件,文件通常会被删除或截断。这两种情况中的任何一种都是不良行为
然后我尝试制作一个工作超过 24 小时但仍然失败一次的排队系统,因此它在某种程度上更稳定。我只知道线程如何工作的基础知识,所以我可能跳过了导致问题的重要事情
函数是这样的
Thread editingThread = null;
public boolean editThreadStarted = false;
HashMap<String, String> queue = new HashMap<>();
public final boolean editParameter(String key, String value)
queue.put(key, value);
if(!editThreadStarted)
editingThread = new Thread(new Runnable()
@Override
public void run()
while(queue.keySet().size() > 0)
String key = (String) queue.keySet().toArray()[0];
String value = queue.get(key);
File inputFile = getFile();
File tempFile = new File(getFile().getName() + ".temp");
try
tempFile.createNewFile();
catch (IOException e)
DemiConsole.error("Failed to create temp file");
handleTrace(e);
continue;
//System.out.println("tempFile.isFile = " + tempFile.isFile());
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile)); BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)))
String currentLine;
while((currentLine = reader.readLine()) != null)
String trimmedLine = currentLine.trim();
if(trimmedLine.startsWith(key))
writer.write(key + ":" + value + System.getProperty("line.separator"));
continue;
writer.write(currentLine + System.getProperty("line.separator"));
writer.close();
reader.close();
inputFile.delete();
tempFile.renameTo(inputFile);
catch (IOException e)
DemiConsole.error("Caught an IO exception while attempting to edit parameter ("+key+") in file ("+getFile().getName()+"), returning false");
handleTrace(e);
continue;
queue.remove(key);
editThreadStarted = false;
);
editThreadStarted = true;
editingThread.start();
return true;
getFile() 返回函数要写入的文件
文件格式是
memberid1:expamount
memberid2:expamount
memberid3:expamount
memberid4:expamount
编辑工作的方式是创建一个临时文件,我将逐行写入原始文件的所有数据,检查 memberid 是否与我要编辑的内容匹配,如果匹配,则不要写入原始文件的行,我将用新的 expamount 编写新的编辑行,然后继续其余行。完成后,将删除原始文件并将临时文件重命名为原始文件,并替换它。
这个函数总是被异步调用,所以让整个事情同步不是一个选项。
提前致谢
编辑(1):
有人建议我使用信号量,在深入研究之后(我以前从未听说过信号量),这似乎是一个非常好的选择,并且无需排队,只需在开始时获取并发布最后,什么都不需要了!
【问题讨论】:
你考虑过同步吗?信号量?有任何顺序化机制吗? 如何使用您提到的队列并让一个线程实际写入文件?此外,根据用户的数量,您可能需要考虑将整个文件保存在内存中(以某种结构)并定期编写新版本(在更新或一堆更新之后)。或者,您可能想考虑某种分片和索引,以便更快地找到需要更新的记录,从而减轻编写器线程的负担。 对于队列系统,其实是我刚刚发布的函数,至于将整个东西存储在hashMap中似乎是最简单的解决方案,我们大约有32k个成员,我不确定它是否会真的很有效率,我会尝试以这种方式实现它,如果遇到任何其他问题,我会回来。谢谢! 【参考方案1】:我最终按照user207421 的建议使用了semaphore
s,它似乎工作得很好
我只是在每行写入之间设置延迟,以人为地使任务更长,并使多个线程同时尝试写入变得更容易,它们都在等待轮到自己!
谢谢
【讨论】:
以上是关于在 Java 中使用异步线程编辑文件的主要内容,如果未能解决你的问题,请参考以下文章