我已经使用Java设计了一个服务器 - 客户应用程序,并且我已连接到服务器多个用户。服务器提供了一些功能,例如:
- 下载文件
- 创建文件
- 写入/附加文件等。
我发现了两个或多个用户发送相同请求时需要同步的一些问题。
例如:当用户想同时下载同一文件时,如何使用同步块或任何其他方法来同步此操作?
//main (connecting 2 users in the server)
ServerSocket server= new ServerSocket(8080, 50);
MyThread client1=new MyThread(server);
MyThread client2=new MyThread(server);
client1.start();
client2.start();
这是我想同步的方法:
//outstream = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));//output to client
//instream = new BufferedReader(new InputStreamReader(sock.getInputStream()));//input from client
public void downloadFile(File file,String name) throws FileNotFoundException, IOException {
synchronized(this)
{
if (file.exists()) {
BufferedReader readfile = new BufferedReader(new FileReader(name + ".txt"));
String newpath = "../Socket/" + name + ".txt";
BufferedWriter socketfile = new BufferedWriter(new FileWriter(newpath));
String line;
while ((line = readfile.readLine()) != null) {
outstream.write(line + "n");
outstream.flush();
socketfile.write(line);
}
outstream.write("EOFn");
outstream.flush();
socketfile.close();
outstream.write("Downloadedn");
outstream.flush();
} else {
outstream.write("FAILn");
}
outstream.flush();
}
}
注意:此方法是在我想在Overriden方法运行中"下载"文件时使用的类,正在使用线程并正在使用。
此示例是否向我保证,当两个用户想下载同一文件时,其中一个必须等待?另一个会得到吗?感谢您的时间!
并发锁定用于提供某些代码的相互排除。为了锁定,您可以用作同步的非结构化锁,例如Reentrantlock等。
任何锁的主要目标是对放置的代码相互排除,这将意味着该作品一次只能通过一个斜向执行。锁内的部分称为关键部分。
要实现适当的锁定,它不足以在此处放置关键代码。另外,您必须确保仅在此处进行关键部分内进行的变量修改。因为如果您锁定了一些代码,但是对内部变量的引用也将传递给一些并发执行线程而无需任何锁定的线程,那么在这种情况下,锁定不会保存您,您将获得数据竞赛。锁仅安全执行关键部分,仅保证您将放置在关键部分中的代码一次仅由一个线程执行。
//utstream = new BufferedWriter(新 outputStreamWriter(sock.getOutputstream((((;//向客户端输出 //instream = new BufferedReader(新 inputStreamReader(sock.getInputStream(((;//来自客户端的输入
public void downloadfile(文件文件,字符串名称(投掷 filenotfoundException,ioexception { 同步(这个( {
该方法的所有者是谁?客户?如果是,那将行不通。您应该锁定同一对象。它应与所有需要锁定的线程共享。但是,在您的情况下,每个客户都会有自己的锁定,而其他线程对其他线程的锁一无所知。您可以锁定客户端。这将起作用。
同步(this(vs同步(myclass.class(
这样做之后,您将有适当的锁定文件来阅读(下载(文件。但是写呢?想象一下,在阅读其他线程时,会想修改该文件时的情况。但是您只能阅读锁。您正在读取文件的开头,另一个线程正在修改其末尾。因此,写入线程将成功,您将在逻辑上获得一个损坏的文件,其中一个文件和另一个文件的末尾乞讨。当然,文件系统和标准Java库尝试照顾此类情况(通过在读者中使用锁,写入锁定,锁定文件偏移等(,但通常这是可能的情况。因此,您还需要同样的锁定。读写方法应共享和使用相同的锁。
,我们已经遇到了正确的行为但性能较低的情况。这是我们的权衡。但是我们可以做得更好。现在,我们为每个写和读取方法都使用相同的锁定,这意味着我们一次只能读取或写入一个文件。但这不是正确的原因,因为我们可以在没有任何可能的损坏的情况下修改或读取不同的文件。因此,更好的方法是将锁与文件不是整个方法相关联。Nio来这里为您提供帮助。
如何使用Java锁定文件(如果可能的话(
https://docs.oracle.com/javase/7/docs/api/java/nio/nio/channels/filelock.html
实际上,如果偏移不同,您可以同时读取文件。由于明显的物理原因,您无法同时读取文件的同一部分。但是同时阅读和关心偏移似乎是一个巨大的开销FMPV,我不确定您是否需要。无论如何,这里有一些信息:同时阅读文件(Java首选(