
- 用戶會要求舉報
- 報告要求將被翻譯成較小的部分
- 每個零件的報告將基于零件/節的類型由報告生成器生成
- 組成報告的各個部分將重新組合成最終報告,并返回給用戶
我的目標是展示如何從錯誤的實施過渡到相當好的實施:
單元測試最好地展示了我擁有的一些基本構建基塊:這是一個測試助手,它生成示例報告請求,其中包括組成報告請求部分:
public class FixtureGenerator {public static ReportRequest generateReportRequest(){List<ReportRequestPart> requestParts = new ArrayList<ReportRequestPart>();Map<String, String> attributes = new HashMap<String, String>();attributes.put("user","user");Context context = new Context(attributes );ReportRequestPart part1 = new ReportRequestPart(Section.HEADER, context);ReportRequestPart part2 = new ReportRequestPart(Section.SECTION1, context);ReportRequestPart part3 = new ReportRequestPart(Section.SECTION2, context);ReportRequestPart part4 = new ReportRequestPart(Section.SECTION3, context);ReportRequestPart part5 = new ReportRequestPart(Section.FOOTER, context); requestParts.add(part1); requestParts.add(part2);requestParts.add(part3);requestParts.add(part4);requestParts.add(part5);ReportRequest reportRequest = new ReportRequest(requestParts );return reportRequest;}}
以及生成報告的測試:
public class FixtureGenerator {@Testpublic void testSequentialReportGeneratorTime(){long startTime = System.currentTimeMillis();Report report = this.reportGenerator.generateReport(FixtureGenerator.generateReportRequest());long timeForReport = System.currentTimeMillis()-startTime;assertThat(report.getSectionReports().size(), is (5));logger.error(String.format("Sequential Report Generator : %s ms", timeForReport));}
生成報告一部分的組件是一個虛擬實現,具有2秒的延遲以模擬IO密集調用:
public class DummyReportPartGenerator implements ReportPartGenerator{@Overridepublic ReportPart generateReportPart(ReportRequestPart reportRequestPart) {try {//Deliberately introduce a delayThread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return new ReportPart(reportRequestPart.getSection(), "Report for " + reportRequestPart.getSection());}
}
順序執行
?
給定這些基本的類集,我的第一個天真的順序實現如下:
public class SequentialReportGenerator implements ReportGenerator {private ReportPartGenerator reportPartGenerator;@Overridepublic Report generateReport(ReportRequest reportRequest){List<ReportRequestPart> reportRequestParts = reportRequest.getRequestParts();List<ReportPart> reportSections = new ArrayList<ReportPart>();for (ReportRequestPart reportRequestPart: reportRequestParts){reportSections.add(reportPartGenerator.generateReportPart(reportRequestPart));}return new Report(reportSections);}......
}
顯然,對于其中包含5個部分的報告請求,每個部分需要2秒鐘才能完成,此報告大約需要10秒鐘才能返回給用戶。
它請求同時進行。
基于原始線程的實現
?
以下是第一個并發實現,雖然不好,但比順序的要好,其后是為每個報告請求部分生成一個線程,等待要生成的報告部分(使用thread.join()方法),并在出現這些塊時對其進行匯總在。
public class RawThreadBasedReportGenerator implements ReportGenerator {private static final Logger logger = LoggerFactory.getLogger(RawThreadBasedReportGenerator.class);private ReportPartGenerator reportPartGenerator;@Overridepublic Report generateReport(ReportRequest reportRequest) {List<ReportRequestPart> reportRequestParts = reportRequest.getRequestParts();List<Thread> threads = new ArrayList<Thread>();List<ReportPartRequestRunnable> runnablesList = new ArrayList<ReportPartRequestRunnable>();for (ReportRequestPart reportRequestPart : reportRequestParts) {ReportPartRequestRunnable reportPartRequestRunnable = new ReportPartRequestRunnable(reportRequestPart, reportPartGenerator);runnablesList.add(reportPartRequestRunnable);Thread thread = new Thread(reportPartRequestRunnable);threads.add(thread);thread.start();}for (Thread thread : threads) {try {thread.join();} catch (InterruptedException e) {logger.error(e.getMessage(), e);}}List<ReportPart> reportParts = new ArrayList<ReportPart>();for (ReportPartRequestRunnable reportPartRequestRunnable : runnablesList) {reportParts.add(reportPartRequestRunnable.getReportPart());}return new Report(reportParts);} .....
}
這種方法的危險在于,將為每個報表部件創建一個新線程,因此在實際情況下,如果同時發出100個請求,并且每個請求都產生5個線程,則可能最終在vm中創建500個代價高昂的線程!!
因此,必須以某種方式限制線程的創建。 在下一篇博客文章中,我將介紹另外兩種控制線程的方法。
參考: 并發–來自JCG合作伙伴 Biju Kunjummen的all和雜物博客, 并發-順序和原始線程 。
翻譯自: https://www.javacodegeeks.com/2012/07/concurrency-sequential-and-raw-thread.html