这个代码线程在ExecutorService中是否安全?

时间:2017-07-13 07:38:10

标签: java multithreading executorservice

public class Test {

    private static final ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        Test test = new Test();
        test.processData("data/test.txt");
    }

    public void processData(String filePath){
        File folder = new File(filePath);
        for (String filename : folder.list()) {
        String filePath = folder.toPath().resolve(filename).toString();
        File inputfile = new File(filePath);

        if (inputfile.isDirectory()) {
            processData(filePath);
        }else{
        pool.execute(() -> {
            log.info("Start processing " + filePath);
            Processor.process(filePath);
        });
    }
  }
}

class Processor{
    private static final Logger log = LoggerFactory.getLogger(Processor.class);

    public static void process(String filePath){

        try{

           List<Document> documets = DocumentProcessor.analyze(filePath);
           ...

        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

class DocumentProcessor{

    private static Tokenizer tokenizer = null;
    private static Resource resource = null;
    private static Checker checker = null;
    private static final ExecutorService pool = Executors.newFixedThreadPool(4);
    static {
       // static initialization here
       // ommited
    }

   public static List<Document> analyze(String filePath){
       BufferedReader br = null;

        List<Document> processedDocs = new ArrayList<>();
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
            String line = null;
            List<Future<Document>> tasks = new ArrayList<>();
            while ((line = br.readLine()) != null) {
                line = line.trim();
                Callable<Document> callable = new FileThread(line, filePath);
                tasks.add(pool.submit(callable));
            }
            for (Future<Document> task : tasks) {
                try {
                    processedDocs.add(task.get());
                } catch (InterruptedException e) {
                    log.error("InterruptedException Failure: " + line);
                } catch (ExecutionException e) {
                    log.error("Thread ExecutionException e: " + line);
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null)
                    br.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return processedDocs;
  } 
}



public class FileThread implements Callable<Document> {

    private String textLine;
    private String filePath;

    public TextThread(String textLine, String filePath) {
        this.textLine = textLine;
        this.filePath = filePath;
    }

    public Document call() {

        ParsedDoc parsedDoc = JSONDocParser.parse(textLine, Source.news);
        Document doc = new Document(parsedDoc.getURL(), parsedDoc.getDocTime());
 doc.setDocument(Parser.parseDoc(parsedDoc.getText());

        return doc;
    }
}

在此代码中,多线程在processData()方法中与ExecutorService类一起使用。我的问题是: 1)在Processor或DocumentProcessor类中是否需要任何类型的线程同步?除了日志变量之外,类'Processor'没有任何实例或类变量。

2)如果这是一个大项目的一部分,并且唯一的多线程代码在Test类中,如此处所示。我是否需要担心所有其他类中的线程问题,假设所有其他类中都没有线程保护。

我问这个的原因是,根据我看到的例子,似乎在这个习惯用法中使用了ExecutorService,我不需要担心所有其他类中的线程问题,即处理器或DocumentProcessor。这是真的吗?

编辑: 请参阅我编辑的代码。我想现在它可以更好地说明我的问题。感谢。

2 个答案:

答案 0 :(得分:2)

仅当一个关键部分由多个线程访问时才需要同步。在您的情况下,您似乎将其作为服务调用,并且在任何其他线程之间没有共享代码。

答案 1 :(得分:0)

您需要做的是使用同步保护代码的关键部分。这意味着,其中您的状态可能同时被多个线程修改。如果您无法访问DocumentProcessor代码,那么您可以围绕对analyze()的调用进行同步,但这可能过于粗糙。如果你的大部分工作都采用那种方法,那么你将失去使用多线程的大部分好处。

理想情况下,analyze()方法应该是线程安全的,因此只有在方法修改DocumentProcessor的静态实例变量的情况下才会进行同步。