我有一个套接字客户端应用程序,它侦听指定端口上主线程中的传入连接,接受传入连接并为每个连接启动用户线程。
此设置可以在某一天运行,然后应用程序停止接受任何新的新连接。恢复的唯一方法是重启应用程序。我不知道为什么会发生这种情况...... 这是我的主要内容,它为每个连接接受并启动一个新线程。
while(ServerOn)
{
ServerSocket myServerSocket;
private static ArrayList<Socket> connecitons;
try {
// Accept incoming connections.
Socket conn = myServerSocket.accept();
// adds the new connections to the socket
connections.add(conn);
// accept() will block until a client connects to the server.
// If execution reaches this point, then it means that a client
// socket has been accepted.
// For each client, we will start a service thread to
// service the client requests.
// Start a Service thread
ServerThread cliThread = new ServerThread(conn);
cliThread.start();
} catch (IOException ioe) {
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
try {
myServerSocket.close();
System.out.println("Server Stopped");
} catch (Exception ioe) {
System.out.println("Problem stopping server socket");
System.exit(-1);
}
}
请帮忙。
编辑1
这是类声明:
class ServerThread extends Thread {
Socket conn;
boolean m_bRunThread = true;
InputStream in = null;
OutputStream outStream = null;
//calling the 1-argument constructor with the socket parameters
ServerThread(Socket s) {
conn = s;
}
//Subclasses of Thread should override this method.
public void run() {
//lot of variables declared here.
try {
// Class InputStream is used for receiving data (as bytes) from client.
in = conn.getInputStream();
// Class OutputStream is used for sending data (as bytes) to client.
outStream = conn.getOutputStream();
/*
* 1. Go to Read Thread
* 2. Check for incoming data stream from Client
* 3. Go to read routine and process only if the data is received from the client
* 4. If there is no data for X minutes then close the socket.
*/
conn.setSoTimeout(time in milliseconds);
String inLine=null;
while (m_bRunThread) {
// read incoming stream
while ((c=in.read(rec_data_in_byte))!= -1)
{...............
并且run方法继续......
答案 0 :(得分:1)
我的观察是基于您提供的上述代码。我在下面看到一些对我来说毫无疑问的事情:
private static ArrayList<Socket> connecitons;
我不需要这份清单。根据代码,我们总是在每个请求的列表中添加conn
个对象。
我们没有在任何地方删除它们(我还没有看到完整的代码)。如果是这种情况,则此列表的大小总是在增长。它可能会导致OutOfMemoryError。
while (m_bRunThread) {....}
在ServerThread类的run()方法中,变量m_bRunThread
是否始终为true。如果是这种情况,则该线程永远不会被终止。所以没有。活线程的数量不断增加。它会使应用程序无响应。
对于ConcurrentModificationException
:因为您没有使用Iterator
(或for-each循环)来迭代列表,所以即使在多线程场景中也不会抛出此异常。
答案 1 :(得分:0)
应删除m_bRunThread
上的外部循环。您只需要内部读取循环,它应该在终止或获得异常时关闭套接字。
答案 2 :(得分:0)
我观察到的另一件事。根据提供的代码,对于每个传入连接,您将创建一个新的服务线程。但我不认为每次创建一个新主题都是个好主意。
因为假设如果每秒有1000个连接,则意味着我们每秒创建新的1000个线程,因此这意味着管理1000个线程需要很大的开销。
由于线程的上下文切换的开销,应用程序可能变得无响应。 其次会有频繁的GC(垃圾收集器)循环,有时可能会导致STW(停止世界)的情况。
所以我的建议是:
你可以使用某种线程池,也可以是Executor框架,我们可以通过提供参数(例如核心池大小,最大池大小,保持空闲线程的活动时间等)来创建我们自己的public class InfixPostfixEvaluator {
/**
* Operators in reverse order of precedence.
*/
private static final String operators = "-+/*";
private static final String operands = "0123456789";
public int evalInfix(String infix) {
return evaluatePostfix(convert2Postfix(infix));
}
public String convert2Postfix(String infixExpr) {
char[] chars = infixExpr.toCharArray();
Stack<Character> stack = new Stack<Character>();
StringBuilder out = new StringBuilder(infixExpr.length());
for (char c : chars) {
if (isOperator(c)) {
while (!stack.isEmpty() && stack.peek() != '(') {
if (operatorGreaterOrEqual(stack.peek(), c)) {
out.append(stack.pop());
} else {
break;
}
}
stack.push(c);
} else if (c == '(') {
stack.push(c);
} else if (c == ')') {
while (!stack.isEmpty() && stack.peek() != '(') {
out.append(stack.pop());
}
if (!stack.isEmpty()) {
stack.pop();
}
} else if (isOperand(c)) {
out.append(c);
}
}
while (!stack.empty()) {
out.append(stack.pop());
}
return out.toString();
}
public int evaluatePostfix(String postfixExpr) {
char[] chars = postfixExpr.toCharArray();
Stack<Integer> stack = new Stack<Integer>();
for (char c : chars) {
if (isOperand(c)) {
stack.push(c - '0'); // convert char to int val
} else if (isOperator(c)) {
int op1 = stack.pop();
int op2 = stack.pop();
int result;
switch (c) {
case '*':
result = op1 * op2;
stack.push(result);
break;
case '/':
result = op2 / op1;
stack.push(result);
break;
case '+':
result = op1 + op2;
stack.push(result);
break;
case '-':
result = op2 - op1;
stack.push(result);
break;
}
}
}
return stack.pop();
}
private int getPrecedence(char operator) {
int ret = 0;
if (operator == '-' || operator == '+') {
ret = 1;
} else if (operator == '*' || operator == '/') {
ret = 2;
}
return ret;
}
private boolean operatorGreaterOrEqual(char op1, char op2) {
return getPrecedence(op1) >= getPrecedence(op2);
}
private boolean isOperator(char val) {
return operators.indexOf(val) >= 0;
}
private boolean isOperand(char val) {
return operands.indexOf(val) >= 0;
}
}
)。所以现在你不必管理线程的创建和生命周期。
现在可以重用空闲线程。
由于频繁的GC的可能性会降低,因此您的应用程序将更具响应性。
即使你可以使用Executor的框架内置固定大小的线程池,实现,你也不需要管理其余的开销,除了你需要通过总数的一件事。 。参数中的线程数,您希望在那里为请求提供服务。
以下是示例代码:
ThreadPoolExecutor
以下是任务实施..
private Executor executor = Executors.newFixedThreadPool(10);
private ArrayList<Socket> connecitons = new ArrayList<>();
while(ServerOn)
{
ServerSocket myServerSocket;
try {
// Accept incoming connections.
Socket conn = myServerSocket.accept();
connections.add(conn);
executor.execute(new ServerThreadRunnable(conn));
} catch (IOException ioe) {
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
try {
myServerSocket.close();
System.out.println("Server Stopped");
} catch (Exception ioe) {
System.out.println("Problem stopping server socket");
System.exit(-1);
}