执行多线程数据库应用程序时发生java.lang.NullPointerException异常

3

创建一个多线程应用程序,该程序创建多个线程并查询同一个数据库表

给定格式为xml的输入文件:

<transliteration>
<element>
    <source>about us</source>
</element>
</transliteration>

该应用程序读取多个文件,为每个xml文件创建一个线程,输出将是另一个具有格式的xml文件。

<transliteration>
<element>
    <source>about us</source>
        <target/>
</element>
</transliteration>

以下是线程的运行方法

public void run() {

        MultipleDatabaseThread th = new MultipleDatabaseThread();
        Map<String,String> map = new HashMap<String,String>();

        try
        {
            Document doc = loadXmlContentToMemory(this.inputString);

            XPathExpression expr = null;
            XPathFactory xFactory = XPathFactory.newInstance();
            XPath xPath = xFactory.newXPath();
            expr = xPath.compile("/transliteration/element//source");
            Object result = expr.evaluate(doc, XPathConstants.NODESET);
            NodeList nodes = (NodeList) result;
            String sourceString = "";
            if(nodes.getLength() > 0)
            {
                for (int i=0; i<nodes.getLength();i++)
                {
                    //System.out.println("Name: "+nodes.item(i).getNodeName() +" Local Name: "+nodes.item(i).getLocalName() +" Value: "+nodes.item(i).getTextContent());
                    sourceString = nodes.item(i).getTextContent();
                    map = th.getCompleteStringTransliterate(sourceString, this.language);

                    if(map.get(sourceString) == null || map.get(sourceString).equals("") || map.get(sourceString).equals(sourceString))
                    {
                        map.clear();
                        map = th.getRecordsFromDatabase(sourceString, language);

                        Element abc = doc.createElement("target");

                        String targetString = "";

                        String[] tokens = sourceString.trim().split("\\s+");

                        for(int itr=0; itr < tokens.length; itr++)
                        {
                            targetString = targetString+" "+map.get(tokens[itr]);
                        }

                        abc.setTextContent(targetString.trim());
                        nodes.item(i).getParentNode().appendChild(abc);
                    }
                    else
                    {
                       Element abc = doc.createElement("target");
                       abc.setTextContent(map.get(sourceString));
                       nodes.item(i).getParentNode().appendChild(abc);
                    }
                }
            }

            try
            {

                expr = xPath.compile("/transliteration/element//target");
                result = expr.evaluate(doc, XPathConstants.NODESET);
            }catch(XPathExpressionException ex)
            {   }

            NodeList nodesList = (NodeList) result;

            for(int i =0;i<nodesList.getLength();i++)
            {
                System.out.println("Node Name: "+nodesList.item(i).getNodeName()+" Node Value: "+nodesList.item(i).getTextContent());
            }

            try
            {
                Transformer transformer = TransformerFactory.newInstance().newTransformer();
                StreamResult strResult = new StreamResult(new File(this.inputString+"_out.xml"));
                if(doc != null && strResult != null)
                {
                    DOMSource source = new  DOMSource(doc);
                    transformer.transform(source, strResult);
                }
            }
            catch(TransformerException ex)
            {
               System.out.println(""+ex);
            }
            catch(TransformerFactoryConfigurationError ex)
            {
               System.out.println(""+ex);
            }

        }catch(IOException ex)
        {
            ex.printStackTrace(System.out);
        }
        catch(DOMException ex)
        {
            ex.printStackTrace(System.out);
        } 
        catch(ParserConfigurationException ex)
        {
            ex.printStackTrace(System.out);
        }
        catch(SAXException ex)
        {
            ex.printStackTrace(System.out);
        }
        catch(XPathExpressionException ex)
        {
            ex.printStackTrace(System.out);
        }
        catch(InterruptedException ex)
        {
            ex.printStackTrace(System.out);
        }

    }
  • loadXmlContentToMemory** function takes filename as a input and loads xml content in the Document.

  • getCompleteStringTransliterate** is a function of MulltipleDatabaseThread class which returns a map variable which contain source and its traget string in it.

  • getRecordsFromDatabase** is anoher function in same class which splits source string and gets its target string again returns map variable

    public class MultipleDatabaseThread {

    public Map<String,String> getCompleteStringTranslate(String inputString, String language) throws InterruptedException
    {
        Map<String,String> map = new HashMap<String,String>();
    
        synchronized(OutputRecords.getMap())
        {
           //long startTime = System.currentTimeMillis();
    
           OutputRecords.clearOutputStream(); 
           Thread thCompleteString = new DatabaseThread(inputString, language);
           thCompleteString.start();
           thCompleteString.join();
    
           map = OutputRecords.getRecords();
           //System.out.println("Complete String Time Taken:: "+(System.currentTimeMillis()-startTime));
           return map;
        }
    }
    
    
    
    public Map<String,String> getRecordsFromDatabase(String inputString, String language) throws  InterruptedException
    {
        String[] tokens = inputString.split("\\s+");
    
        Map<String,String> map = new HashMap<String,String>();
    
        Thread[] databaseThreads = new Thread[tokens.length];
    
        synchronized(OutputRecords.getMap())
        {
            //long startTime = System.currentTimeMillis();
    
            OutputRecords.clearOutputStream();
            for(int index=0; index < tokens.length; index++)
            {
                databaseThreads[index] = new DatabaseThread(tokens[index],language);
                databaseThreads[index].start();
            }
            for(int index = 0 ; index < tokens.length; index++)
            {
                    databaseThreads[index].join();
            }
    
            map = OutputRecords.getRecords();
            //System.out.println("Tokens Time Taken:: "+(System.currentTimeMillis()-startTime));
    
            return map;
    
        }
    }
    

    }

这两个函数使用OutputRecord类中的静态/共享映射变量,并生成多个线程,这些线程实际上调用数据库并填充共享映射变量,然后返回该变量。但是,在执行此程序时,它会产生错误。
Exception in thread "Thread-0" java.lang.NullPointerException
    at transliterationthreading.ExecuteOuterThread.run(ExecuteOuterThread.java:66)

在线
if(map.get(sourceString) == null || map.get(sourceString).equals("") || map.get(sourceString).equals(sourceString))

所以一个线程被终止,然后其他线程完全执行并生成输出文件。我不明白问题在哪里,请问有人能提供解决此问题的建议吗?
谢谢

1
当该线程正在运行时,我怀疑map为空。map = OutputRecords.getRecords();导致它为空吗? - sanbhat
OutputRecords.getRecords(); 返回静态映射变量,该变量在类加载时初始化,它可能为空,但我不知道何时它可能为null。 - Nishit Jain
你尝试过将map变量声明为volatile吗? - Jk1
如果这是一个共享的静态映射,那么你不应该从多个线程同时读写它。 - JB Nizet
@JB Nizet,那么我如何从线程的run方法中返回值呢? - Nishit Jain
你应该研究一下Callables。它们允许从调用方法返回值。在Executor中运行可维护的Callables更容易。这样,你就不需要共享Map,也不必担心其他线程会干扰它。 - Kurtymckurt
2个回答

0

我会怀疑在评估该行时地图内容发生了变化

if(map.get(sourceString) == null || map.get(sourceString).equals("") || map.get(sourceString).equals(sourceString))

这样你的空指针检查就会成功,但是从 map 获取到的新值可能为空。Map 不同步!

将此行更改为

String sourceStringValue = map.get(sourceString);
if(sourceStringValue == null || sourceStringValue.equals("") || map.get(sourceString).equals(sourceString))

我也尝试过那种方法,但对我没用。然而,我通过移除共享映射方法并使用ExecutorService和Callable接口解决了问题,并通过调用call()方法返回每个线程的值。感谢大家的努力。 - Nishit Jain

0

感谢大家的努力。

我尝试使用不使用静态共享映射,而是使用ExecutorService和Callable接口方法来解决这个问题。

以下是我的代码:

try
        {
            doc = loadXmlContentToMemory(this.inputString);
            expr = xPath.compile("/transliteration/element//source");
            result = expr.evaluate(doc, XPathConstants.NODESET);

        }catch(ParserConfigurationException ex)
        {
            System.out.println("loadXmlError: "+ex.toString());
        }
        catch(IOException ex)
        {
            System.out.println("loadXmlError: "+ex.toString());
        }
        catch(SAXException ex)
        {
            System.out.println("loadXmlError: "+ex.toString());
        }
        catch(XPathExpressionException ex)
        {
            System.out.println("loadXmlError: "+ex.toString());
        }

        NodeList nodes = (NodeList) result;
        String sourceString = "";

        if(nodes.getLength() >0)
        {
            Map<String,String> fileMap = new HashMap<String,String>(); 
            ExecutorService executor = Executors.newFixedThreadPool(NTHREADS);

            for(int index =0; index <nodes.getLength(); index++)
            {
                sourceString = nodes.item(index).getTextContent();
                Callable<Map<String,String>> worker = new MultipleDatabaseCallable(sourceString,language);
                Future<Map<String,String>> map = executor.submit(worker);

                try
                {
                    //System.out.println(""+Thread.currentThread().getName()+"SourceString:: "+sourceString+"Map: "+map.get().get(sourceString));
                      fileMap.putAll(map.get());
                }catch(InterruptedException ex)
                {
                    System.out.println("future read: "+ex.toString());
                }
                catch(ExecutionException ex)
                {
                    System.out.println("future read: "+ex.toString());
                }
            }

            executor.shutdown();
            // Wait until all threads are finish
            while (!executor.isTerminated()) {

            }
            ExecutorService tokenExecutor = Executors.newFixedThreadPool(NTHREADS);
            for(int i =0 ;i<nodes.getLength();i++)
            {
                sourceString = nodes.item(i).getTextContent();
                if(fileMap.get(sourceString) == null || fileMap.get(sourceString).equals("") || fileMap.get(sourceString).equals(sourceString))
                {
                    fileMap.remove(sourceString);
                    Callable<Map<String,String>> worker = new MultipleTokenCallable(sourceString,language);
                    Future<Map<String,String>> map = tokenExecutor.submit(worker);

                    try
                    {
                        fileMap.putAll(map.get());
                    }
                    catch(InterruptedException ex)
                    {
                        System.out.println("Tokenized put Interupted exception: "+ex.toString());
                    }
                    catch(ExecutionException ex)
                    {
                        System.out.println("Tokenized put Execution exception: "+ex.toString());
                        ex.printStackTrace(System.out);
                    }

                    Element targetElement = doc.createElement("target");
                    String targetString = "";

                    String[] tokens = sourceString.trim().split("\\s+");

                    for(int itr=0; itr < tokens.length; itr++)
                    {
                        targetString = targetString+" "+fileMap.get(tokens[itr]);
                    }
                    targetElement.setTextContent(targetString.trim());
                    nodes.item(i).getParentNode().appendChild(targetElement);
                    //System.out.println(""+Thread.currentThread().getName()+" Target:  "+targetString+" Source:  "+sourceString);
                }
                else
                {
                    Element abc = doc.createElement("target");
                    abc.setTextContent(fileMap.get(sourceString));
                    nodes.item(i).getParentNode().appendChild(abc);
                }
            }

            tokenExecutor.shutdown();
            // Wait until all threads are finish
            while (!tokenExecutor.isTerminated()) {

            }
            try
            {
                Transformer transformer = TransformerFactory.newInstance().newTransformer();
                StreamResult strResult = new StreamResult(new File(this.inputString+"_out.xml"));
                if(doc != null && strResult != null)
                {
                    DOMSource source = new  DOMSource(doc);
                    transformer.transform(source, strResult);
                }
            }
            catch(TransformerException ex)
            {
               System.out.println(""+ex);
            }
            catch(TransformerFactoryConfigurationError ex)
            {
               System.out.println(""+ex);
            }

        }

由于使用此方法会生成多个线程,所有线程都尝试同时连接数据库,如果并发线程数增加,可能会导致太多连接错误。因此,您需要维护一个连接池来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接