【Socket】三、Socket使用線程池支持多個線程同時訪問
一、使用循環不斷接受客戶端發送的消息
首先將第二節的TCPServer改造,使用while(true)讓服務器能夠一直接收客戶端發送的信息。
同時使用try-finally語法塊關閉連接。
public class TcpServer {
public static void main(String[] args) throws IOException {
System.out.println("socket服務器端啓動....");
ServerSocket serverSocket = new ServerSocket(8088);
try {
while (true){
//獲取客戶端對象
Socket accept = serverSocket.accept();
InputStream inputStream = accept.getInputStream();
byte[] buf= new byte[1024];
int len=inputStream.read(buf);
String str =new String(buf,0,len);
System.out.println("str:" + str);
}
} finally {
serverSocket.close();
}
}
}
使用瀏覽器不斷訪問 http://127.0.0.1:8088/ 地址,控制檯會一直打印訪問信息。
缺點:只能支持一個客戶端訪問,無法支持多個同時訪問。
二、使用線程池優化訪問
注意這裏爲什麼不使用多線程而是線程池。因爲線程池可以放入緩存隊列。線程池其實就是多線程,提前提供了線程放入線程池,調用時供調用方使用,會出個專題專門講線程池,這裏只說使用。
在之前代碼基礎上,添加了線程池,此時代碼可供多個客戶端同時訪問,So easy!
public static void main(String[] args) throws IOException {
System.out.println("socket服務器端啓動....");
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
ServerSocket serverSocket = new ServerSocket(8088);
try {
while (true){
//獲取客戶端對象
Socket accept = serverSocket.accept();
newCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
InputStream inputStream = accept.getInputStream();
byte[] buf= new byte[1024];
int len=inputStream.read(buf);
String str =new String(buf,0,len);
System.out.println("str:" + str);
//給瀏覽器反饋數據
OutputStream outputStream = accept.getOutputStream();
outputStream.write("this is my socket - TCP - Test".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
} finally {
serverSocket.close();
}
}
三、使用Lambda優化線程池匿名內部類
這裏是個小插曲 以第二部的建立線程代碼爲例,咋們把建立過程使用lambda替換
注意lambda只存在於 JDK 1.8及以上!
二段代碼原文:
newCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
InputStream inputStream = accept.getInputStream();
byte[] buf= new byte[1024];
int len=inputStream.read(buf);
String str =new String(buf,0,len);
System.out.println("str:" + str);
//給瀏覽器反饋數據
OutputStream outputStream = accept.getOutputStream();
outputStream.write("this is my socket - TCP - Test".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
});
使用lambda優化後的代碼
newCachedThreadPool.execute(new Thread(()->{
try {
InputStream inputStream = accept.getInputStream();
byte[] buf= new byte[1024];
int len=inputStream.read(buf);
String str =new String(buf,0,len);
System.out.println("str:" + str);
//給瀏覽器反饋數據
OutputStream outputStream = accept.getOutputStream();
outputStream.write("this is my socket - TCP - Test".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}));
可以看到代碼簡潔了不少。
然而更直觀點我們可以這樣
//Lambda
newCachedThreadPool.execute(new Thread(()->{
System.out.println(1);
}));
//匿名內部類
newCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(1);
}
});