【问题标题】:Program never ends but Thread Pool claims to shut down程序永远不会结束,但线程池声称要关闭
【发布时间】:2014-05-03 19:37:48
【问题描述】:

我遇到了一个多线程程序的问题。

我需要模拟很多人试图在同一时间预订同一航班,不使用任何锁。

所以我创建了一个 ExecutorService 并用它来池线程,这样我就可以同时进行许多尝试。

但问题是,程序在打印出所有结果之前就到达了终点,它只是坐在那里并永远运行。我试图进入所有其他使用数据库连接的类,并简单地手动关闭它们。没有运气。

package dbassignment4;

   import java.util.ArrayList;
   import java.util.List;
   import java.util.concurrent.ExecutionException;
   import java.util.concurrent.ExecutorService;
   import java.util.concurrent.Future;
   import java.util.concurrent.LinkedBlockingQueue;
   import java.util.concurrent.RejectedExecutionException;
   import java.util.concurrent.ThreadPoolExecutor;
   import java.util.concurrent.TimeUnit;

   /**
    *
    * @author Vipar
    */
   public class Master{

   private static final int POOL_SIZE = 50;
   public static boolean planeIsBooked = false;
   /**
    * @param args the command line arguments
    */
   public static void main(String[] args) {

       int success = 0;
       int seatNotReserved = 0;
       int seatNotReservedByCustomerID = 0;
       int reservationTimeout = 0;
       int seatIsOccupied = 0;
       int misc = 0;

       HelperClass.clearAllBookings("CR9");
       Thread t = new Thread(new DBMonitor("CR9"));
       long start = System.nanoTime();
       //HelperClass.clearAllBookings("CR9");
       ExecutorService pool = new ThreadPoolExecutor(
               POOL_SIZE, POOL_SIZE,
               0L,
               TimeUnit.MILLISECONDS,
               new LinkedBlockingQueue<Runnable>(POOL_SIZE));
       int threadsStarted = 0;
       List<Future<Integer>> results = new ArrayList<>();
       long id = 1;
       t.start();
       while(planeIsBooked == false) {
           try {
           Future<Integer> submit = pool.submit(new UserThread(id));
           results.add(submit);
           } catch (RejectedExecutionException ex) {
               misc++;
               continue;
           }
           threadsStarted++;
           id++;
       }
       pool.shutdownNow();

       int count = 0;
       for(Future<Integer> i : results) {
           try {
               switch(i.get()) {
                   case 0:
                       // Success
                       success++;
                       break;
                   case -1:
                       // Seat is not Reserved
                       seatNotReserved++;
                       break;
                   case -2:
                       // Seat is not Reserved by Customer ID
                       seatNotReservedByCustomerID++;
                       break;
                   case -3:
                       // Reservation Timeout
                       reservationTimeout++;
                       break;
                   case -4:
                       // Seat is occupied
                       seatIsOccupied++;
                       break;
                   default:
                       misc++;
                       // Everything else fails
                       break;
               }
           } catch (ExecutionException | InterruptedException ex) {
               misc++;
           }
           count++;
           System.out.println("Processed Future Objects: " + count);
           // HERE IS WHERE IT LOOPS
       }

下面是它不会立即执行的其余代码:

long end = System.nanoTime();
long time = end - start;
System.out.println("Threads Started: " + threadsStarted);
System.out.println("Successful Bookings: " + success);
System.out.println("Seat Not Reserved when trying to book: " + seatNotReserved);
System.out.println("Reservations that Timed out: " + reservationTimeout);
System.out.println("Reserved by another ID when trying to book: " + seatNotReservedByCustomerID);
System.out.println("Bookings that were occupied: " + seatIsOccupied);
System.out.println("Misc Errors: " + misc);
System.out.println("Execution Time (Seconds): " + (double) (time / 1000000000));
}
}

你能发现问题吗?我在代码停止运行的地方添加了注释。

【问题讨论】:

  • 永远永远这样做:planeIsBooked == falseplaneIsBooked == (true == false) 更具可读性。或planeIsBooked == (1 == 2 == true)。你明白了。
  • 为什么要关闭池?
  • 我没有看到你停止Thread t。还要使用Executors 中的工厂方法,而不是构造函数。
  • @salyh 你好,我是最初想提交问题的人,但是我今天问的太多了。基本上我们关闭了游泳池,因为我们现在实现了预订飞机上每个座位的目标。
  • Further planeIsBooked 不是 volatile,因此如果您从其他线程更新它,此更改将不可见。基本上,这段代码都是错的……

标签: java multithreading ojdbc


【解决方案1】:

planeIsBooked 变成true 时,看起来你的planeIsBooked 永远不会在while 循环中初始化为true。所以请确保你的循环不是无限的。

【讨论】:

  • DBMonitor 单独检查 planeIsBooked 并将该变量刷新为 true(有效)。
【解决方案2】:

第一件事是while(planeIsBooked == false) 总是评估为真,因为

planeIsBooked = false always , nowhere its initialized to true. 

那么你的 while 循环条件怎么会变成假并出来呢?

在 while 循环中设置 planeIsBooked = true 以退出 while 循环。

【讨论】:

  • 你有没有调试检查 planeIsBooked 设置 false 的值?因为在多线程环境中,为了使变量值在我们使用 volatle 的线程中保持一致,但似乎你还没有这样做......所以它可能会向 arraylist 结果添加无限值......请检查 while 循环是否运行 nfinitely ?
【解决方案3】:

几件事:

首先,在您致电pool.shutdownNow(); 之后,您将尝试立即获取结果。调用 shutDownNow() 不会阻塞,也不是池已停止的明确指示。为此-您应该致电pool.awaitTermination()

其次,不清楚你的评论是什么意思 -

// 这里是循环的地方

这是一个循环 - 并查看循环 - 如果在 switch case 中抛出异常 - 那么它将进入 catch - 忽略它并循环。你检查异常了吗?

【讨论】:

    【解决方案4】:

    通过answer 了解为什么在多线程环境中应将静态变量声明为 volatile。

    即使你的静态变量是易变的,以下几行也是危险的

    while(planeIsBooked == false) {
            Future<Integer> submit = pool.submit(new UserThread(id));
       }
    

    考虑您的预订航班平均需要 2 秒。你有大约 300 个座位(假设)。您的 planeIsBooked 字段将在 600 秒后变为真(如果它在单线程中运行)。使用 50 个大小的池,它将在 12 秒内运行。

    根据上述假设,您的循环将运行 12 秒。 现在,想想提交请求语句执行了多少次?我次。 即使您只有 300 个席位,您也可能会在 12 秒内发出大约更多的最少百万个请求。

    因此,在调用 Shutdown now() 之前考虑一下队列中的作业数。这不是终止循环的正确方法

    如果你知道你的飞行座位的最大尺寸,为什么不在for循环中使用它(可能是在for循环中外部化参数,而不是变量来保存

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-25
      • 1970-01-01
      • 1970-01-01
      • 2014-11-26
      • 2018-04-09
      • 1970-01-01
      相关资源
      最近更新 更多