使用单独的线程更新全局Hashmap时出现Nullpointer异常

时间:2018-07-17 09:52:26

标签: java multithreading nullpointerexception global-variables

我在Hashmap中得到了一个N​​ull指针异常,这是一个全局变量,并通过单独的线程进行更新。在调试时,所有线程都可以正常运行并更新Hashmap,但是当我执行程序时,一个线程会抛出Null指针。

public class RunEngine {

	/**
	 * @param args
	 */

	public static Map<Integer, List<Event>> queue_map = new HashMap<Integer, List<Event>>();

	public static void main(String[] args) {


		/*
		 * check file present in data set folder or not , if present fetch the file name
		 * and store then in a list
		 */
		File folder = new File(ConfigurationParameters.FOLDER_PATH);
		File[] listOfFiles = folder.listFiles();

		/* Create a thread pool for number of Publishers which you want to initialise */
		ThreadPoolExecutor executor = new ThreadPoolExecutor(ConfigurationParameters.P_NUMBER,
				ConfigurationParameters.P_NUMBER + 3, 100, TimeUnit.MILLISECONDS,
				new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());   // P_NUMBER = 2

		for (int i = 1; i <= ConfigurationParameters.P_NUMBER; i++) {

			ConnectP conn = new ConnectP(
					ConfigurationParameters.FOLDER_PATH + "\\" + listOfFiles[i - 1].getName(),
					ConfigurationParameters.DISTRIBUTION_RANDOM, i);
			executor.execute(conn);
		}
		executor.shutdown();

		

	}

}

ConnectP类如下:

public class ConnectP implements Runnable {

    private String file_path;
    private String distribution_constant;
    private int pub_id;

    /**
     * @param file_path
     * @param distribution_constant
     */
    public ConnectP(String file_path, String distribution_constant, int pub_id) {
        super();
        this.file_path = file_path;
        this.distribution_constant = distribution_constant;
        this.pub_id = pub_id;
    }

    public void streamevent(List<Event> eventlist, String distributionconstant)
            throws InterruptedException {


        if (distributionconstant.matches(ConfigurationParameters.PUBLISHER_DISTRIBUTION_RANDOM)) {

            List<Event> publisherqueue = new ArrayList<>();
            RunEngine.queue_map.put(pub_id, publisherqueue);
            for (Event event : eventlist) {
                long start = System.currentTimeMillis(); // get present system timestamp
                event.setTimeStamp(start);
                publisherqueue.add(event); // add to publisher queue
                Random rand = new Random();
                int value = rand.nextInt(1000); // add a random seed for streaming
                Thread.sleep(value); // sleep the process for that value
                System.out.println("Publisher " + String.valueOf(pub_id) + " : " + RunEngine.queue_map.get(pub_id).size()); **(throwing exception line 68)**


            }

        }


    }
    // function to connect to source file and return list of publication event
    public List<Event> connectsource(String filepath) {
        // return list after reading file
        return list;
    }


    @Override
    public void run() {
        // TODO Auto-generated method stub

        List<Event> event = this.connectsource(file_path); // connect to source
        try {
            System.out.println("THREAD " + String.valueOf(pub_id)+ " Initiated");
            this.streamevent(event, distribution_constant);**(throwing exception line 121)**
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

我得到的例外是

Exception in thread "pool-1-thread-1" java.lang.NullPointerException
	at org.test.event.ConnectP.streamevent(ConnectP.java:68)
	at org.test.event.ConnectP.run(ConnectP.java:121)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

感谢您的帮助。如果有一些有效的方法可以做到这一点,将不胜感激。

2 个答案:

答案 0 :(得分:1)

  

我在Hashmap中得到了一个N​​ull指针异常,这是一个全局变量,并且正在通过单独的线程进行更新。

HashMap不是同步类。如果多个线程同时更新该映射,则它们的该映射的内存视图很可能会不同步,这可能导致NPE,无限循环或其他不良情况。

实现此目的最简单的方法是使用ConcurrentHashMap类,该类为您处理同步。

// thread-1   
RunEngine.queue_map.put(pub_id, publisherqueue);
...
// thread-2
RunEngine.queue_map.get(pub_id).size()

对。一个线程看起来像在推销,而另一个线程正在变得。当您在多个线程中执行此操作时,您需要担心:

  • 内存可见性以确保一个线程中的映射更改被其他线程看到。
  • 进行锁定以确保两个线程不会同时更改地图,并且它们的更新发生冲突。

基本上,每个线程在每个处理器上都有一个本地内存缓存,使它可以高效地访问缓存的结果,而不必从主内存中获取所有内容。因此,当线程1更新地图时,它只能在缓存中这样做。如果然后从线程2获取线程2,则它可能看不到任何更新,或者更糟的是,根据虚拟内存详细信息,该映射的部分更新。如果两个线程都在更新映射,则将其内存缓存刷新到主内存的那个将覆盖另一个线程所做的更新。

对于在线程之间共享的 any 对象,这是正确的。只有具有最终字段的不可变对象可以在线程之间共享,而不必担心。否则,您需要使用volatilesynchronized关键字以确保正确共享它们。要正确地做到这一点非常困难,并且需要Java线程和内存同步结构方面的丰富经验。

Java tutorial about synchronization可能是入门的好地方。

答案 1 :(得分:0)

您可以将并发HashMap用于线程安全。