Desidero utilizzare le classi SOAPConnectionFactory e MessageFactory da SAAJ con più thread, ma risulta che non posso presumere che siano thread-safe. Alcuni Related posts:Creazione di un oggetto non thread-thread per thread e utilizzo della garanzia before-before
Ecco un po 'la prova interessante che può essere thread-safe: http://svn.apache.org/repos/asf/axis/axis2/java/core/tags/v1.5.6/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java si dice
Anche se la sicurezza dei thread non è esplicitamente richiesto dalle specifiche SAAJ, sembra che il SOAPConnection nell'implementazione di riferimento di Sun è thread-safe.
Ma ancora non penso che sia una prova sufficiente per trattare le classi SAAJ come thread-safe.
Quindi la mia domanda: l'idioma è corretto? Creo esattamente un oggetto SOAPConnection e MessageFactory utilizzando le possibili fabbriche non thread-thread all'interno del thread principale e quindi pubblichiamo in modo sicuro tali oggetti su un'attività executor utilizzando la garanzia first-before dell'interfaccia di CompletionService. Uso anche questo, prima di garantire di estrarre l'oggetto HashMap risultato.
Fondamentalmente voglio solo verificare la sanità mentale del mio ragionamento.
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;
}
Ora non si sta creando istanza per thread, ma istanza per attività (quindi verranno create 100 istanze di ciascuna). Perché non usi 'TreadLocal' per ridurre l'istanziazione e riutilizzarli in compiti non interferenti? –
Mi chiedo solo: perché utilizzi un main static per il test; e non i test unitari? – GhostCat
@SashaSalauyou Sì, istanza per compito in realtà. Ma non penso che cambi molto. In teoria, potrei creare un oggetto all'interno di "submit" e un po 'nasconderlo dentro ThreadLocal per il caso in cui un'altra attività viene eseguita all'interno dello stesso thread, ma dovrò comunque richiamare almeno SOAPConnectionFactory.newInstance() all'interno del codice dell'attività blocco che si assume qui per non essere thread-safe. Fammi sapere se mi manca qualcosa. Inoltre, non mi interessa "riutilizzarli" così tanto. La chiamata di servizio è di circa 1 minuto per la mia situazione, quindi la velocità di creazione degli oggetti non è un collo di bottiglia. – Ruslan