2016-11-18 65 views
3

a simple test case我已經實現一個線程池服務器在端口12345接收多達10個同時傳入TLS PSK連接和印刷在標準輸出解密後的數據:如何預先分配線程池服務器的對象?

public static void main(String[] args) throws IOException { 
    ServerSocket server = new ServerSocket(12345); 
    ExecutorService pool = Executors.newFixedThreadPool(10); 

    while (true) { 
     Socket socket = server.accept(); 
     pool.execute(new MyRunnable(socket)); 
    } 
} 

這裏是由螺紋使用的Runnable實現:

@Override 
public void run() { 
    try { 
     SecureRandom random  = new SecureRandom();  // How to preallocate? 
     BufferedInputStream bis = new BufferedInputStream(mSocket.getInputStream()); 
     BufferedOutputStream bos = new BufferedOutputStream(mSocket.getOutputStream()); 
     TlsServerProtocol proto = new TlsServerProtocol(bis, bos, random); 
     MockPSKTlsServer server = new MockPSKTlsServer(); // How to preallocate? 
     proto.accept(server); 
     Streams.pipeAll(proto.getInputStream(), System.out); 
     proto.close(); 
    } catch (IOException e) { 
     System.err.print(e); 
    } 
} 

如何預分配由Runnable使用的SecureRandomMockPSKTlsServer對象?

I.e.如何在main()中創建兩個對象中的10個,然後在run()中重新使用它們?

+1

你使用哪個版本的Java? –

+0

我使用Windows和Linux –

回答

3

在你的情況我會用一個ThreadLocal爲每個類(SecureRandomMockPSKTlsServer),能有SecureRandomMockPSKTlsServer一個專用實例連接池的每個線程和重用他們,當線程將不得不執行相同類型的任務,但輸入Socket,例如:

private static final ThreadLocal<SecureRandom> random = ThreadLocal.withInitial(
    SecureRandom::new 
); 
private static final ThreadLocal<MockPSKTlsServer> server = ThreadLocal.withInitial(
    MockPSKTlsServer::new 
); 

... 
public void run() { 
    try (BufferedInputStream bis = new BufferedInputStream(mSocket.getInputStream()); 
     BufferedOutputStream bos = new BufferedOutputStream(mSocket.getOutputStream()); 
     TlsServerProtocol proto = new TlsServerProtocol(bis, bos, random.get())) { 
     // Calling server.get() will get the instance dedicated to the current 
     // thread, if no instance exists so far for this thread 
     // new MockPSKTlsServer() will automatically be called then 
     // affected to this thread for subsequent get's calls 
     proto.accept(server.get()); 
     ... 
    } catch (IOException e) { 
     System.err.print(e); 
    } 
} 

注意:使用try-with-resources語句自動關閉您的輸入/輸出流。

+0

如果我在[MyRunnable.java](https://github.com/afarber/jetty-newbie/tree/master)中創建'random'和'server'變量** static **/TlsPskServer2/src/main/java/de/afarber/tlspskserver2)並且擁有該類的10個實例 - 它們不會被所有10個實例使用嗎?我很好奇爲什麼你在這裏建議** static **?因爲我需要爲我的池中的每個線程預先分配10個'SecureRandom'和'MockPSKTlsServer'實例... –

+1

不,它必須是**靜態**,否則您的'ThreadLocal'將無用。您應該閱讀關於'ThreadLocal'的javadoc,簡而言之,'ThreadLocal'用於將給定類的實例範圍化爲'Thread',換句話說,線程1將從'ThreadLocal'獲得的內容將會不同從什麼線程2會得到。所以如果你有10個線程在'ThreadLocal'上調用'get()','ThreadLocal'實際上會管理你的類的10個實例(每個線程一個)。 –

2

通常我會使用ThreadLocal<>並使用輕量級的Pool<T>類來保存和提供實例。

我不認爲這是一個Pool<T>開箱即用,但這是平凡的構建。

ThreadLocal<>的唯一考慮因素是您必須確保正確釋放回Pool<>。所以,如果你認爲這傳達給另一個線程的,更好的方法可以是共享的靜態池,但無論是用鎖定(如果你沒有太在意性能)或併發的容器,如果你做..

話雖如此:http://commons.apache.org/proper/commons-pool/

+0

[Java SE的1.8(https://github.com/afarber/jetty-newbie/blob/master/TlsPskServer2/pom.xml)其實,我不與其他線程溝通。我讀取傳入的數據,解密並關閉套接字。從長遠來看,我想通過另一個套接字將解密的數據轉發到嵌入式Jetty(不能[TLS PSK](https://en.wikipedia.org/wiki/TLS-PSK))。即我正在嘗試爲Jetty編寫一個線程池「反向代理」。 –

+0

那麼,你不需要一個游泳池,看起來你只需要一個實例 - 在這種情況下 - 忽略關於游泳池的東西,並將其直接粘貼在一個'ThreadLocal <>'中。 – Nim

+0

我想我需要一個游泳池 - 對於多個傳入連接... –