我应该如何设计该程序?

时间:2019-02-22 11:23:27

标签: java multithreading java-8

我正在用Java编写程序。图片是不言自明的-

Design main方法产生三个线程。 SAX处理器处理输入的XML文件,生成JAXB对象,并将其放入guava缓存中。 Guava缓存由另一个线程处理。每当有任何对象进入高速缓存时,该线程都会通知第三个线程,即MDL生成器(它与相似的JAXB对象相关,将它们互连并生成另一个XML文件,称为MDL)。我已经为主类编写了以下代码-

package test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainClass {

    public static void main(String args[]) {

        ExecutorService xMLService = Executors.newFixedThreadPool(1);
        xMLService.execute(new XMLProcessor());

        ExecutorService cacheService = Executors.newFixedThreadPool(1);
        cacheService.execute(new CacheProcessor());

        ExecutorService mdlService = Executors.newFixedThreadPool(1);
        mdlService.execute(new MDLProcessor());

        xMLService.shutdown();
        cacheService.shutdown();
        mDLService.shutdown();
    }
}

但是,现在我对如何在线程之间传递对象以及每当有新对象进入缓存时如何通知MDL生成器感到怀疑。在Java旧线程模型中,我们可以使用notify(),但是我想使用当前的ExecutorService。并且有异步回调。所以我想知道如何设计这个框架。如何传递对象并通知线程?我们将缓存对象保留在HashMap中,并且CacheService线程需要将密钥传递给MDLService。那么我应该使用哪种模式?

3 个答案:

答案 0 :(得分:4)

  

如何传递对象并通知线程?我们将缓存对象保留在HashMap中,并且CacheService线程需要将密钥传递给MDLService。那么我应该使用哪种模式?

在我看来,您有1个线程太多。 XML读取线程和MDL编写很有意义,但是仅将内容放入内存缓存的线程似乎太复杂了。如果MDL生成器需要使用Guava缓存,则应“拥有”缓存并将其粘贴。

剩下1条输入SAX处理器线程和1条输出MDL生成器线程。好。要连接两者,我将使用BlockingQueue之类的LinkedBlockingQueue。您可能希望或不希望对队列设置大小限制,具体取决于读取的速度是否比书写的速度快以及作业中有多少条记录。

因此,您的主线程将创建BlockingQueue,然后将其传递给输入和输出线程。 SAX输入线程调用队列上的put(),MDL输出线程调用take()将对象放入Guava缓存中,然后生成MDL。

希望这会有所帮助。

答案 1 :(得分:3)

由于使用的是Guava缓存,因此可以使用Guava AsyncEventBus在任务之间分配消息,并取消三个单独的专用ExecutorServices。

答案 2 :(得分:2)

这是上述情况的示例实现。请注意,正如其他一些答复中提到的那样,即使没有Guava缓存也可以实现。不过,我认为Nirmalaya可能有正当理由要求它。我可以考虑的原因之一就是将缓存溢出到存储设备或数据库,以节省运行时内存。

employee-records.xml

<?xml version="1.0" encoding="UTF-8"?>
<Employees>
    <Employee id="1">
        <name>Thomas</name>
    </Employee>
    <Employee id="2">
        <name>Lisa</name>
    </Employee>
    <Employee id="3">
        <name>Ronald</name>
    </Employee>
    <Employee id="4">
        <name>Erica</name>
    </Employee>
</Employees>

Employee.java

package com.technoroy.examples.guava;

/**
 * A value holder POJO implementation for Employee records
 * @author Rahul R
 *
 */
class Employee {
    private Integer id = null;
    private String name = null;

    public Employee() {
        super();
    }

    public Employee(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + "]";
    }
}

GuavaCacheProcessor.java

package com.technoroy.examples.guava;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

/**
 * The primary executable class
 * 
 * @author Rahul R
 *
 */
public class GuavaCacheProcessor {
    private final static BlockingQueue<Integer> notificationQueue = new LinkedBlockingQueue<>();

    public static void main(String... arguments) {
        Runnable xmlProcessor = new Runnable() {
            public void run() {
                parseDataFile();
            }
        };

        Runnable mdlGenerator = new Runnable() {
            public void run() {
                try {
                    while (true) {
                        Integer id = notificationQueue.take();
                        Employee record = ApplicationCacheUtil.getRecord(id);
                        generateContent(record);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        };

        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(xmlProcessor);
        executorService.submit(mdlGenerator);
    }

    public static void generateContent(Employee employee) {
        System.out.println(employee);
    }

    public static void parseDataFile() {
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        InputStream dataInputStream = GuavaCacheProcessor.class.getResourceAsStream("employee-records.xml");

        try {
            SAXParser saxParser = saxParserFactory.newSAXParser();
            saxParser.parse(dataInputStream, new DefaultHandler() {
                private Employee employee = null;
                private StringBuilder elementValue = null;

                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes)
                        throws SAXException {
                    if (qName.equalsIgnoreCase("Employee")) {
                        employee = new Employee();

                        String id = attributes.getValue("id");
                        if (id.matches("-?\\d+(\\.\\d+)?")) {
                            employee.setId(Integer.valueOf(id));
                        }
                    }

                    elementValue = new StringBuilder();
                }

                @Override
                public void characters(char ch[], int start, int length) throws SAXException {
                    if (elementValue != null) {
                        elementValue.append(new String(ch, start, length));
                    }
                }

                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    if (qName.equalsIgnoreCase("name")) {
                        if (employee != null && elementValue != null) {
                            employee.setName(elementValue.toString());
                        }
                    } else if (qName.equalsIgnoreCase("Employee")) {
                        ApplicationCacheUtil.putRecord(employee.getId(), employee);
                        try {
                            notificationQueue.put(employee.getId());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    elementValue = null;
                }
            });
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }
    }
}

/**
 * The Cache utilities class, that initializes and returns a handle to the
 * cache.
 * 
 * @author Rahul R
 *
 */
class ApplicationCacheUtil {
    private static Cache<Integer, Employee> cache = CacheBuilder.newBuilder().build();

    public static Cache<Integer, Employee> getCache() {
        return cache;
    }

    public static void putRecord(Integer key, Employee value) {
        cache.put(key, value);
    }

    public static Employee getRecord(Integer key) {
        return cache.getIfPresent(key);
    }
}