【问题标题】:How to achieve Synchronization in Multithreading Java App如何在多线程 Java App 中实现同步
【发布时间】:2017-04-25 09:51:42
【问题描述】:

我已经使用 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("EOF\n");
        outstream.flush();
        socketfile.close();
        outstream.write("Downloaded\n");
        outstream.flush();
    } else {
        outstream.write("FAIL\n");
    }
    outstream.flush();

  }
}

注意:此方法位于扩展 Thread 的类中,当我想在覆盖的方法 Run() 中“下载”文件时使用此方法


此示例是否向我保证,当 2 个用户想要下载同一个文件时,其中一个必须等​​待?另一个人会得到吗?感谢您的宝贵时间!

【问题讨论】:

标签: java multithreading


【解决方案1】:

并发锁定用于为某些代码提供互斥。对于锁定,您可以使用像 ReentrantLock 等非结构化锁一样同步。

任何锁的主要目标是为放置在其中的一段代码提供互斥,这意味着这段代码一次只能由一个线程执行。锁内的部分称为临界区。

要实现正确的锁定,仅在此处放置关键代码是不够的。此外,您必须确保仅在关键部分对变量进行修改。因为如果你锁定了一些代码,但是对内部变量的引用也被传递给了一些并发执行的线程而没有任何锁定,那么在这种情况下锁定不会拯救你,你会遇到数据竞争。锁只保护临界区的执行,并且只保证放置在临界区的代码一次只能由一个线程执行。

//outstream = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));//输出到客户端 //instream = new BufferedReader(new InputStreamReader(sock.getInputStream()));//来自客户端的输入

public void downloadFile(File file,String name) throws FileNotFoundException, IOException { 同步(这个) {

这个方法的所有者是谁?客户?如果是,那么它将不起作用。您应该锁定同一个对象。它应该与所有需要锁定的线程共享。但是在您的情况下,每个客户端都将拥有自己的锁,而其他线程对其他线程的锁一无所知。您可以锁定在 Client.class。这将起作用。

synchronize(this) vs synchronize(MyClass.class)

完成此操作后,您将获得适当的锁定以读取(下载)文件。但是写呢?想象一下在读取其他线程时想要修改该文件的情况。但是您的锁仅用于阅读。您正在读取文件的开头,而另一个线程正在修改它的结尾。因此,写入线程将成功,您将在逻辑上得到一个损坏的文件,其中一个文件的请求和另一个文件的结尾。当然,文件系统和标准 java 库会尝试处理这种情况(通过在 reader\writes 中使用锁,锁定文件偏移量等),但通常这是一种可能的情况。所以你也需要同样的写锁。并且读写方法应该共享和使用同一个锁。

我们遇到了一种行为正确但性能低下的情况。这是我们的权衡。但我们可以做得更好。现在我们为每个写入和读取方法使用相同的锁,这意味着我们一次只能读取或写入一个文件。但这是不正确的,因为我们可以修改或读取不同的文件而不会造成任何损坏。所以更好的方法是将锁与文件而不是整个方法相关联。 nio 来帮你。

How can I lock a file using java (if possible)

https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html

实际上,如果偏移量不同,您可以同时读取文件。由于明显的物理原因,您不能同时读取文件的同一部分。但是并发读取和处理偏移量似乎是一个巨大的开销 fmpv,我不确定你是否需要它。无论如何,这里有一些信息:Concurrent reading of a File (java preferred)

【讨论】:

    猜你喜欢
    • 2017-12-08
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-17
    相关资源
    最近更新 更多