【问题标题】:java threads are null when join() is called调用 join() 时 java 线程为空
【发布时间】:2015-05-06 03:06:04
【问题描述】:

对于家庭作业,我正在为一个管理多个执行事务的线程的服务器编写一个 stop() 方法。 Stop() 应该 1. 向命令队列提交停止命令和 2. 在所有线程上调用 join() 以便事务有机会完成。

但是,join() 没有按预期工作。当我尝试调用 join() 时,我得到一个 NullPointerException。我将服务器线程修改为在提交停止命令后等待一秒钟,但是当我应该使用 join() 时,这是一个糟糕的替代品。

public void stop() throws InterruptedException {
    // TODO Auto-generated method stub

    System.out.println("server stop()");
    for (CommandExecutionThread thread : threads) { 
        System.out.println(threads.length);
    }

    for (CommandExecutionThread thread : threads) { 

        Command e = new CommandStop();
        queue.add(e);

    }   

    for (CommandExecutionThread thread : threads) { 
        if (thread != null) 
        {
            thread.join(); 
        } 
        if (thread == null)
        {
            System.out.println("NULL thread"); //threads are always null at this point 
        }
    }

    for (CommandExecutionThread thread : threads) { 
        System.out.println(threads.length);
    }
    wait(1000);//simulate the wait that I would have had from join() 

}

CommandExecutionThreads poll() 来自commandQueue的命令,当遇到停止命令时返回:

public void run() {
    while (true) { 
        synchronized (commandQueue) {
            while (commandQueue.isEmpty()) { 
                try {
                    commandQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }//end while(commandQueue.isEmpty())
        }//end synchronized(commandQueue)

        Command c; 

        synchronized (commandQueue) { 

            c = commandQueue.poll(); 

            if (c.isStop()==true)
            { 
                System.out.println("\tSTOP");
                return;
            } 
            else 
            { 
                //System.out.println("\tTRANSACTION"); 
            } 

            if (executeCommandInsideMonitor) { 
                try {
                    c.execute(bank);
                } catch (InsufficientFundsException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            commandQueue.notifyAll();
        } // end sync commandQueue 
    } //end while(true)
}//end run() 

我在创建银行服务器时较早地初始化了我的线程数组。当它们变得可用时,线程本身将命令从队列中拉出。出于诊断目的,我打印了 thread.isAlive() 并且有效。当我在 stop 方法中时,thread.isAlive() 抛出一个空指针错误:

public class BankServerImpl implements BankServer {
Queue<Command> queue = new LinkedList<Command>(); 
CommandExecutionThread[] threads; 
boolean executeCommandInsideMonitor; 
Bank bank; 

/**
 * Constructor for BankServerImpl, which implements BankServer
 * 
 * @param bank
 * @param serverThreads
 * @param executeCommandInsideMonitor
 */
public BankServerImpl(Bank bank, int serverThreads, boolean executeCommandInsideMonitor) {

    this.bank = bank; 
    this.executeCommandInsideMonitor = executeCommandInsideMonitor;
    threads = new CommandExecutionThread[serverThreads]; 

    for(CommandExecutionThread thread : threads) { 
        thread = new CommandExecutionThread(bank, queue, executeCommandInsideMonitor);
        thread.start(); 
        System.out.println(thread.isAlive());   

    }
}

【问题讨论】:

  • threads 声明在哪里,什么写入了值?如果它包含空值,那很可能是因为您根本没有初始化它。
  • if (thread == null) { System.out.println("NULL thread"); //threads are always null at this point } 上面没有显示初始化线程数组的代码,可能它从未初始化过,请检查您的代码。
  • 您正在将空值 放入 您的线程集合/数组。再次取出时仍然为空。
  • 如果线程是null,很可能你还没有初始化数组的值。
  • 我相信我在构造函数期间初始化了我的数组中的线程。我已经更新了原始帖子以包含该代码。

标签: java multithreading terminate


【解决方案1】:

当您创建线程时,您永远不会将它们插入到数组中。

for(CommandExecutionThread thread : threads) { 
    thread = new CommandExecutionThread(bank, queue, executeCommandInsideMonitor);
    thread.start(); 
    System.out.println(thread.isAlive());   
}

此代码不会导致数组更新。你需要这样的东西:

for (int i = 0; i < serverThreads; i += 1) {
    CommandExecutionThread newThread = new CommandExecutionThread(bank, queue, executeCommandInsideMonitor);
    threads[i] = newThread;
    newThread.start();
    System.out.println(newThread.isAlive()); 
}

【讨论】:

  • 仅供参考,使用 ArrayList 会更好。使用集合更容易和更清洁。
  • 谢谢!在我看到 for 循环的并排比较之前,我并没有点击它。现在这完全有道理了...非常感谢您提供的解决方案以及使用集合的提示。
  • 没问题@LWang。顺便说一句,如果您认为这是一个可以接受的答案,如果您将其标记为回答您的问题,我将不胜感激。
  • 完成!这是我第一次在 StackOverflow 上发帖,所以感谢您如此迅速地回答我的问题并帮助我学习正确的礼仪。你有我的绿色支票!
  • 没问题。我想你会发现有很多人愿意提供帮助。不要让一票否决让您灰心。
猜你喜欢
  • 2018-05-30
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多