【问题标题】:Reading and writing in files with Thread and semaphore使用线程和信号量读取和写入文件
【发布时间】:2015-02-28 04:56:59
【问题描述】:

我是信号量的新手,我有任何问题。我有一个线程,它从文本文件 A 开始并读取行并将它们写入其他文本文件 B。我编写了这段代码,但我不确定线程​​是否阻塞关键部分并正确同步。因为和其他线程可以操作这些文件。

public static void main(String[] args)  {

            Thread thread = new Thread(new ThreadManager());
            thread.start();

      }

线程类:

public class ThreadManager extends Thread {
      private Semaphore semaphore;

      public ThreadManager() {
            this.semaphore = new Semaphore(1);
      }

      public void run() {

            try {
                  this.semaphore.acquire();

                  BufferedReader br = null;
                  String line;
                  String fileNme = "threadLog.txt";
                  ArrayList<String> fileLines = new ArrayList<String>();
                  int numLine = 0;

                  File outFile = new File("$$$$$$$$.tmp");

                  // input
                  FileInputStream fis = null;
                  PrintWriter out = null;
                  try {
                        fis = new FileInputStream(fileNme);

                        // output
                        FileOutputStream fos = new FileOutputStream(outFile);
                        out = new PrintWriter(fos);
                  } catch (FileNotFoundException e2) {
                        // TODO Auto-generated catch block
                        e2.printStackTrace();
                  }
                  BufferedReader in = new BufferedReader(new InputStreamReader(fis));

                  try {
                        while ((line = in.readLine()) != null) {
                              fileLines.add(line);
                        }
                  } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                  }

                  if (!fileLines.isEmpty()) {
                        int middleLine = (int) Math.round(fileLines.size() / 2);
                        fileLines.add(middleLine, Thread.currentThread().getName());

                        for (int i = 0; i < fileLines.size(); i++) {
                              out.println(fileLines.get(i));
                        }

                        out.flush();
                        out.close();
                        try {
                              in.close();
                              new File(fileNme).delete();
                              outFile.renameTo(new File(fileNme));
                        } catch (IOException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                        }

                  }
                   this.semaphore.release();
            } catch (InterruptedException e3) {
                  // TODO Auto-generated catch block
                  e3.printStackTrace();
            }

      }

【问题讨论】:

  • 考虑使用using {...} 块。
  • 考虑使用同步。不过,这不会阻止 其他 代码接触文件。
  • @Scary Wombat Synchronized 只允许一个执行线程同时访问资源。信号量允许最多 n 个(您可以选择 n 个)执行线程同时访问资源。但是信号量对我的任务来说是不必要的吗?
  • @Fortran 不清楚您的任务是什么。例如,您真的希望多个线程同时写入同一个文件吗?
  • @Fortran 您只指定了带有 1 个执行线程的信号量,在我看来这会导致复杂的同步

标签: java multithreading semaphore


【解决方案1】:

您不能保证对文件的同步访问,仅给定文件名,使用信号量或同步块(或其他)。任何其他线程(或进程)仍然可以打开、读取或修改该文件,例如通过创建自己的FileOutputStream 并传递相同的文件名。

虽然您当然可以构建您的代码以鼓励同步访问文件,但至少在您的进程中,您不能保证它。因此,您必须对其他进程访问您的文件的可能性做出一些假设,并定义(并记录)一些关于其他线程如何访问文件并遵守它们的规则。

看起来您只是在制作一个临时文件,因此您也可以考虑File.createTempFile() 以减少使用相同文件名的可能性;为文件名添加唯一性可能会有所帮助。

虽然我肯定可以更详细地介绍特定选项,但是从您的问题中并不清楚您的确切用途,并且没有更多信息,我能告诉您的最好的信息是同步原语不能用于 100% 保证没有其他人同时访问该文件 - 您必须考虑您的情况,并在通过代码提供这种保护与良好的文档和遵守您定义的规则之间找到平衡。

顺便说一句,具有 1 个许可的信号量与互斥锁相同,在这种情况下,您可能会发现 synchronized blocks 提供了更吸引人的语法。

也不要忘记ReadWriteLock,这是另一个有用的工具,具体取决于您的访问模式和性能要求。

【讨论】:

  • 我如何确定其他线程正在同时访问该文件?这是我的问题!
  • 更多信息:我有一个线程在同一个文件中读取和插入新行。我必须同步该文件,以便没有其他线程不会同时访问该文件。这是我将如何同步文件记录,因为当其他线程写入时。
  • @Fortran 您可能不应该为此使用文件。考虑例如使用 List 而不是文件将数据存储在内存中,可能是预制的同步容器之一,或者使用 ReadWriteLock 或同步块自己保护它。
【解决方案2】:

我找到了Class FileChannel,现在我正在开发此代码。你有什么意见?

public class ThreadManager extends Thread {
    FileChannel f = null; // The channel to the file
    FileLock lock = null; // The lock object we hold

    public void run() {
        try {
            BufferedReader br = null;
            String line;
            String fileNme = "threadLog.txt";
            ArrayList<String> fileLines = new ArrayList<String>();
            int numLine = 0;

            File outFile = new File("$$$$$$$$.tmp");

            // input
            FileInputStream fis = null;
            PrintWriter out = null;
            try {
                fis = new FileInputStream(fileNme);

                     f = fis.getChannel();
                lock = f.tryLock();

      if (lock != null) {
            // output
                FileOutputStream fos = new FileOutputStream(outFile);
                out = new PrintWriter(fos);
            } catch (FileNotFoundException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            }
            BufferedReader in = new BufferedReader(new InputStreamReader(fis));

            try {
                while ((line = in.readLine()) != null) {
                    fileLines.add(line);
                }
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

            if (!fileLines.isEmpty()) {
                int middleLine = (int) Math.round(fileLines.size() / 2);
                fileLines.add(middleLine, Thread.currentThread().getName());

                for (int i = 0; i < fileLines.size(); i++) {
                    out.println(fileLines.get(i));
                }

                out.flush();
                out.close();
                try {
                    in.close();
                    new File(fileNme).delete();
                    outFile.renameTo(new File(fileNme));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
      }

            }

     } finally {
      // Always release the lock and close the file
      // Closing the RandomAccessFile also closes its FileChannel.
      if (lock != null && lock.isValid())
        lock.release();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 2011-06-09
    • 2023-04-01
    相关资源
    最近更新 更多