SAAJ の SOAPConnectionFactory および MessageFactory クラスを複数のスレッドで使用したいのですが、それらがスレッドセーフであると想定できないことがわかりました。関連する投稿:
これがスレッドセーフであるという興味深い小さな証拠があります: http://svn.apache.org/repos/asf/axis/axis2/java/core/tags/v1.5.6/modules/saaj/src/org/apache /axis2/saaj/SOAPConnectionImpl.java という
SAAJ 仕様ではスレッド セーフは明示的に要求されていませんが、Sun の参照実装の SOAPConnection はスレッド セーフであるようです。
それでも、SAAJ クラスをスレッドセーフとして扱うには十分な証拠ではないと思います。
だから私の質問:以下のイディオムは正しいですか?メイン スレッド内でスレッド セーフでない可能性があるファクトリを使用して SOAPConnection オブジェクトと MessageFactory オブジェクトを 1 つだけ作成し、CompletionService インターフェイスの事前発生保証を使用して、これらのオブジェクトをエグゼキュータ タスクに安全に発行します。また、この事前発生保証を使用して、結果の HashMap オブジェクトを抽出します。
基本的には、自分の推論の正気を確認したいだけです。
public static void main(String args[]) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletionService<Map<String, String>> completionService = new ExecutorCompletionService<>(executorService);
//submitting 100 tasks
for (int i = 0; i < 100; i++) {
// there is no docs on if these classes are thread-safe or not, so creating them before submitting to the
// external thread. This seems to be safe, because we are relying on the happens-before guarantees of the
// CompletionService.
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = soapConnectionFactory.createConnection();
MessageFactory messageFactory = MessageFactory.newInstance();
int number = i;// we can't just use i, because it's not effectively final within the task below
completionService.submit(() -> {
// using messageFactory here!
SOAPMessage request = createSOAPRequest(messageFactory, number);
// using soapConnection here!
SOAPMessage soapResponse = soapConnection.call(request, "example.com");
soapConnection.close();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
soapResponse.writeTo(outputStream);
// HashMap is not thread-safe on its own, but we'll use the happens-before guarantee. See f.get() below.
Map<String, String> result = new HashMap<>();
result.put("soapResponse", new String(outputStream.toByteArray()));
return result;
});
}
// printing the responses as they arrive
for (int i = 0; i < 100; i++) {
Future<Map<String, String>> f = completionService.take();
Map<String, String> result = f.get();
System.out.println(result.get("soapResponse"));
}
executorService.shutdown();
}
/**
* Thread-safe static method
*/
private static SOAPMessage createSOAPRequest(MessageFactory messageFactory, int number) throws Exception {
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
String serverURI = "example.com";
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("example", serverURI);
SOAPBody soapBody = envelope.getBody();
SOAPElement soapBodyElem = soapBody.addChildElement("number", "example");
soapBodyElem.addTextNode(String.valueOf(number));
soapMessage.saveChanges();
return soapMessage;
}