【问题标题】:Synchronizing threads so files load consecutively in Java同步线程,以便在 Java 中连续加载文件
【发布时间】:2023-04-04 09:16:01
【问题描述】:

我必须加载文件并打印其中的数据,但线程都是并行运行的,所以几秒钟后只显示最后一个文件中的数据。总共有七个文件,我正在循环加载它们。

这是我的代码:

 public class thread extends Thread {

     private static final String String = null;
     static String file="Lab5File";
     static String output="test2.dat";
     static ArrayList<Thread> threadList = new ArrayList<Thread>();


 public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {

  threadList = new ArrayList<>();

     for (int l=1;l<8;l++ )  
     {

        thread1111 x = new thread1111(file+l+".dat");
        threadList.add(x);
        x.start();
     }

     try {
         int ch = System.in.read();

     } catch (IOException e) {
       // TODO Auto-generated catch block
        e.printStackTrace();
     }

 } 


 public static class thread1111 extends Thread {
    String name ; 

    static DataOutputStream dos ;
    static FileOutputStream fos;
    static ArrayList<Thread> threadList;


    public thread1111(String fileName)
    {
        name = fileName;

          try {
            fos = new FileOutputStream("test2.dat");

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        dos = new DataOutputStream(fos);

    }

    public void run(){  

         InputStream is = null;
         DataInputStream dis = null;

         System.out.println("TRYING.........");

         try{

            // create input stream from file input stream
            is = new FileInputStream(name);

            // create data input stream
            dis = new DataInputStream(is);

        while (true) synchronized(dos)  {

                int Zip = dis.readInt();
                String City = dis.readUTF();
                String State = dis.readUTF();
                double Longitude =dis.readDouble();
                double Latitudes=dis.readDouble();
                int Zone = dis.readInt();
                int dst = dis.readInt();

                dos.writeInt(Zip);
                dos.writeUTF(City);
                dos.writeUTF(State);
                dos.writeDouble(Longitude);
                dos.writeDouble(Latitudes);
                dos.writeInt(Zone);
                dos.writeInt(dst);

               System.out.println(Zip+"\t"+City+"\t"+State+"\t"+Longitude+"\t"+Latitudes+"\t"+Zone+"\t"+dst+"\n");

            }

         }catch(Exception e){
                // if any I/O error occurs
                e.printStackTrace();
             }finally{

                // releases any associated system files with this stream
                if(is!=null)
                    try {
                        is.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                if(dis!=null)
                    try {
                        dis.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
             }   
   } 

 }}

【问题讨论】:

  • 如果你想一个接一个地加载文件,你为什么要使用线程?
  • 加载文件将受到 I/O 限制,我认为执行并行读取毫无意义。特别是如果您想按顺序输出它们。
  • 添加和概括已经说过的内容,如果任务 A 和任务 B 总是一起发生,但是您不能开始任务 B,直到您完成 任务 A,那么在单独的线程中执行任务是没有意义的。如果这是一个学习线程的练习,那么这是一个不好的例子,因为它与线程的用途完全相反。同步线程是必要的邪恶。您的目标应该始终是使用可以避免的最少同步量来解决问题,并且仍然保证程序会做正确的事情。

标签: java multithreading io


【解决方案1】:

几个选项,

  1. 您可以使用Thread.join

  2. 您可以使用CyclicBarrier 来同步您的线程。

  3. Single thread executor 有足够大的队列 (7) 以满足您的需求。

【讨论】:

    【解决方案2】:
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Test {
    
        public static void main(String[] args) {
    
            ExecutorService service = Executors.newFixedThreadPool(7);
            ReentrantLock lock = new ReentrantLock(true);
            for (int i = 0; i < 7; i++) {
                service.execute(new Runner("File" + i, lock));
            }
            service.shutdown();
        }
    
    }
    
    class Runner implements Runnable {
        String fileName;
        ReentrantLock lock;
    
        public Runner(String name, ReentrantLock lock) {
            this.fileName = name;
            this.lock = lock;
        }
    
        @Override
        public void run() {
            lock.lock();
            System.out.println("Current Thread: "
                    + Thread.currentThread().getName() + " Executing file: "
                    + fileName);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            lock.unlock();
        }
    
    }
    

    将您的代码放入 Runnable 类的 run 方法中以打印文件数据并根据您自己的需要进行更改。

    【讨论】:

      【解决方案3】:

      仅仅使用Thread类,你需要调用join()来同步线程:

      Thread1.start();
      Thread1.join();
      Thread2.start();
      Thread2.join();
      Thread3.start();
      Thread3.join();
      ...
      

      您可以将主循环更改为

      for (int l=1;l<8;l++ )  
         {
          thread1111 x = new thread1111(file+l+".dat");
          // threadList.add(x);
          x.start();
          x.join()
          }
      

      然后循环不会迭代到下一个线程,直到当前线程完成 - 当然你可以把整个循环放到它自己的线程中

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 2011-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多