调用线程池的shutdownNow()方法后,不能中断任务中被阻塞的I/O,为什么,怎么办?

夜雨双唱2016 2016-06-16 06:22:08
代码如下:

package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ServerMian {

public static void main(String[] args) {
ServerMian test = new ServerMian();
test.run();
}

private volatile boolean runFlag = true;
private ServerSocket server = null;
private ExecutorService pool = null;
private int poolSize = 10;

public void run() {
init();
work();
}

public void init() {
try {
server = new ServerSocket(12505);
} catch (IOException e) {
System.out.println("建立监听时发生错误:" + e.toString());
System.exit(-1);
}

pool = Executors.newFixedThreadPool(poolSize);

System.out.println("服务器正常启动。");
}

public void work() {

try {

while(runFlag){
Socket client = server.accept();
if(runFlag){
Task task = new Task(client);
pool.execute(task);
}
}

System.out.println("服务器端关闭中...");

pool.shutdown();
try {
System.out.println("time1:" + new Date());
pool.awaitTermination(2000, TimeUnit.MILLISECONDS);
System.out.println("time2:" + new Date());
} catch (InterruptedException e) {

}

if(!pool.isTerminated()){
System.out.println("线程池未结束。");
pool.shutdownNow();
try {
System.out.println("time3:" + new Date());
pool.awaitTermination(3000, TimeUnit.MILLISECONDS);
System.out.println("time4:" + new Date());
} catch (InterruptedException e1) {
System.out.println("强制关闭失败");
}
}

try {
this.server.close();
System.out.println("监听套接字被关闭");
} catch(Exception e) {
System.out.println("关闭套接字错误:" + e.toString());
} finally {
this.server = null;
}

} catch (IOException e) {
System.out.println("服务器端发生错误" + e);
}

}

public void closeServer() throws IOException {
Socket closesocket = new Socket("127.0.0.1", 12505);
closesocket.close();
}

class Task extends Thread {

private Socket client = null;
private BufferedReader reader = null;
private BufferedWriter writer = null;
private boolean err = false;

public Task(Socket client) {
this.client = client;
String msg = "新的连接到来 => [" + client.getRemoteSocketAddress() + " ---> " + client.getLocalAddress() + ":" + client.getLocalPort() + "]";
System.out.println(msg);

try {
this.reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch (IOException e) {
System.out.println("输入流错误:" + e.toString());
err = true;
}

try {
this.writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
} catch (IOException e) {
System.out.println("输出流错误:" + e.toString());
err = true;
}
}

@Override
public void run() {
if(err){
return;
}

try {
writer.write("欢迎光临。");
writer.newLine();
writer.flush();
} catch (IOException e) {
System.out.println("输出流错误:" + e.toString());
return;
}

try {

String line = "";
while((line = reader.readLine()) != null){
System.out.println("服务器端接收到的信息:" + line);
if("exit".equals(line.trim().toLowerCase()) || "quit".equals(line.trim().toLowerCase())){
runFlag = false;
this.reader.close();
this.writer.close();
this.client.close();
closeServer();
break;
}else{
writer.write("RE: " + line);
writer.newLine();
writer.flush();
}
}

} catch (IOException e) {
System.out.println(this.client.getRemoteSocketAddress() + "连接错误:" + e.toString());
}

System.out.println("会话结束");
}
}
}


服务器端的处理启动后,用cmd命令行启动2个窗口,分别用telnet 命令进行连接,
然后在一个命令行窗口中输入:exit, 这时候服务器端会关闭。
但是根据eclipse的运行状态来看,服务器端并没有关闭,还在运行,并且另一个命令行窗口还能继续通信,这是为什么?
应该怎么正确关闭服务器的线程池?

...全文
474 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
夜雨双唱2016 2016-06-17
  • 打赏
  • 举报
回复
恩,只能用关闭IO的办法中断阻塞,我想了一个比较笨的方法,就是用一个map存储所有socket连接,当关闭服务器端的时候,将map中所有的socket连接关闭,具体如下: 1. 当一个连接到来,放到线程池中运行的时候,就将连接的socket存储到一个ConcurrentHashMap中。 2. 当线程池中运行的任务结束的时候,将存储在ConcurrentHashMap中对应的socket移除。 3. 关闭服务器的时候,遍历ConcurrentHashMap,将其中存储的socket全部关闭。 代码如下:
package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ServerProcess {
	
	// 运行标记
	private volatile boolean runFlag = true;
	
	// 服务器监听用套接字
	private ServerSocket server = null;
	// 监听端口
	private int port = 12505;
	
	// 处理连接的线程池对象
	private ExecutorService pool = null;
	// 线程池的线程数
	private int poolSize = 10;
	
	// 存储socket连接用Map(用来强制关闭线程池用)
	private ConcurrentHashMap<String, Socket> socketMap = new ConcurrentHashMap<String, Socket>();
	
	public static void main(String[] args) {
		ServerProcess proc = new ServerProcess();
		proc.run();
	}
	
	/**
	 * 服务运行
	 */
	public void run() {
		init();
		listen();
		close();
	}
	
	/**
	 * 初始化处理
	 */
	public void init() {
		try {
			server = new ServerSocket(this.port);
		} catch (IOException e) {
			System.out.println("建立监听时发生错误:" + e.toString());
			System.exit(-1);
		}
		
		pool = Executors.newFixedThreadPool(poolSize);
		
		System.out.println("服务器启动!");
		System.out.println("监听端口号:" + this.port);
	}
	
	/**
	 * 监听处理
	 */
	public void listen() {
		while(runFlag){
			try {
				Socket client = server.accept();
				if(runFlag){
					Task task = new Task(client);
					pool.execute(task);
				}
			} catch (Exception e) {
				System.out.println("服务器的监听处理发生错误:" + e);
			}
		}
	}
	
	/**
	 * 停止服务器端的监听
	 * @throws IOException
	 */
	private void stopServerListen() throws IOException {
		runFlag = false;
		Socket client = new Socket("127.0.0.1", this.port);
		client.close();
	}
	
	/**
	 * 关闭服务器
	 */
	private void close() {
		closeServerSocket();
		closePool();
		System.out.println("服务器停止!");
	}
	
	/**
	 * 关闭线程池
	 */
	private void closePool() {
		pool.shutdown();
		try {
			pool.awaitTermination(100, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {}
		
		if(!pool.isTerminated()){
			pool.shutdownNow();
			try {
				pool.awaitTermination(100, TimeUnit.MILLISECONDS);
			} catch (InterruptedException e) {}
		}
		
		if(!pool.isTerminated()){
			if(!socketMap.isEmpty()){
				for(String key : socketMap.keySet()){
					Socket socket = socketMap.get(key);
					try {
						socket.close();
					} catch (IOException e) {
						socket = null;
					}
				}
			}
			
			try {
				pool.awaitTermination(100, TimeUnit.MILLISECONDS);
			} catch (InterruptedException e) {}
		}
	}
	
	/**
	 * 关闭监听套接字
	 */
	private void closeServerSocket() {
		try {
			server.close();
		} catch (IOException e) {
			
		} finally {
			server = null;
		}
	}
	
	/**
	 * 任务处理类
	 */
	class Task implements Runnable {
		
		private Socket client = null;
		private BufferedReader reader = null;
		private BufferedWriter writer = null;
		
		public Task(Socket client) {
			this.client = client;
		}
		
		/**
		 * 关闭处理
		 */
		private void close() {
			
			// 将套接字从Map中移除
			socketMap.remove(Thread.currentThread().getName());
			
			// 关闭套接字
			if(client != null){
				try {
					client.close();
					System.out.println("与客户端[" + client.getRemoteSocketAddress() + "]的连接已经断开");
				} catch (Exception e) {
					System.out.println("连接[" + client.getRemoteSocketAddress() + "]关闭时发生错误:" + e);
				} finally {
					client = null;
				}
			}
		}

		/**
		 * 会话处理
		 */
		@Override
		public void run() {
			
			// 将套接字保存到Map
			socketMap.put(Thread.currentThread().getName(), this.client);
			System.out.println("目前持有的连接情报:" + socketMap);
			
			try {
				
				// 读入流
				this.reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
				// 输出流
				this.writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
				
				// 向客户端推送欢迎消息
				writer.write("welcome!");
				writer.newLine();
				writer.flush();
				
				// 接受来自客户端的消息并作出反应
				String line = "";
				while((line = reader.readLine()) != null){
					
					System.out.println("服务器的线程[" + Thread.currentThread().getName() + "]接收到来自【" + this.client + "】的信息:" + line);
					
					String editLine = line.trim().toLowerCase();
					if("stop".equals(editLine)){
						// 关闭服务器
						stopServerListen();
						break;
					}else if("exit".equals(editLine) || "quit".equals(editLine)) {
						// 关闭会话
						break;
					}else{
						// 发送回执消息
						writer.write("RE: " + line);
						writer.newLine();
						writer.flush();
					}
				}
				
			} catch (IOException e) {
				if(runFlag){
					System.out.println("与客户端[" + client.getRemoteSocketAddress() + "]的会话发生错误:" + e);
				}
			} finally {
				close();
			}
		}
	}
}
solo陈 2016-06-17
  • 打赏
  • 举报
回复
加个finally,io用close()方法关闭
夜雨双唱2016 2016-06-16
  • 打赏
  • 举报
回复
好吧,我记错了,原来有些操作是不能用interrupt()中断的,如下: 以下是不可中断阻塞的情况: java.io包中的同步Socket I/O java.io包中的同步I/O Selector的异步I/O 获取某个锁

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧