基本上,我正在调用BufferedReader.ReadLine();但是我在多线程服务器中,我正在同步树中的节点。因此,当调用此ReadLine函数时,如果其他人到达该节点,则它们将被锁定。我无法弄清楚如何在退出线程之前ReadLine等待响应的时间限制。我得到的最接近的是创建一个睡眠1ms的新线程,然后检查我设置ReadLine的变量是否改变了。所以像这样:
synchronized (pointer) {
String answer = "";
Thread d = new Thread(new Runnable() {
public void run() {
try {
int i = 0;
while (answer.equals("")) {
if (i == 10000) {
System.out.println("Timeout Occured");
System.exit(0);
}
try {
Thread.sleep(1);
i++;
}
catch(Exception e) {
System.out.println("sleep problem occured");
}
}
}
catch (IOException ex) {
}
}
});
d.start();
answer = socketIn.readLine();
}
这就是我想要的,但我无法弄清楚如何阻止当前线程解锁节点,以便其他用户可以继续而不是杀死整个服务器。最后,我想也许我可以这样做:
Thread d = new Thread(new Runnable() {
public void run() {
try {
answer = socketIn.readLine();
} catch (IOException ex) {
}
}
});
d.join(10000);
catch (InterruptedException e){
socketOut.println("Timeout Occured. Returning you to the beginning...");
socketOut.flush();
return;
}
但这仍然似乎阻止而且无法继续。有人可以帮我解决这个问题吗?我无法理解我做错了什么?
我也尝试让ExecutorService工作,但不能。这是我的答案吗?我该如何实现它?
[编辑] socketIn是一个BufferedReader,应该说明确抱歉。 此外,客户端通过telnet连接,但我认为不重要。
我在这里做的是一个“名人猜谜游戏”,用户可以在树上添加名人。所以我需要锁定该人正在为线程安全编辑的节点
答案 0 :(得分:3)
这是家庭作业吗?它与我昨天提出的问题非常接近。如果是这样,它应该有家庭作业标签。
当线程修改其他线程可能读取/修改的数据时,您只需要锁定某些内容。
如果您在输入时锁定某些内容,则锁定的范围太宽。
你的流程应该是:
(假设你的每个连接/客户端都有一个线程,并且阻止从客户端读取)
话虽如此......如果您正在从套接字读取并希望它超时,则需要在第一次接受连接时使用clientSocket.setSoTimeout(1000);
。如果您的BufferedReader
正在等待该时间量(以毫秒为单位)并且未获得输入,则会抛出java.net.SocketTimeoutException
String inputLine = null;
try
{
inputLine = in.readLine();
if (inputLine == null)
{
System.out.println("Client Disconnected!");
}
else
{
// I have input, do something with it
}
}
catch(java.net.SocketTimeoutException e)
{
System.out.println("Timed out trying to read from socket");
}
答案 1 :(得分:1)
一切都已经完成。尝试使用java.util.concurrent
。
//
// 1. construct reading task
//
final FutureTask<String> readLine = new FutureTask<String> (
new Callable<String>() {
@Override public String call() throws Exception {
return socketIn.readLine();
}
}
);
//
// 2. wrap it with "timed logic"
// *** remember: you expose to your users only this task
//
final FutureTask<String> timedReadLine = new FutureTask<String> (
new Callable<String>() {
@Override public String call() throws Exception {
try {
//
// you give reading task a time budget:
// try to get a result for not more than 1 minute
//
return readLine.get( 1, TimeUnit.MINUTES );
} finally {
//
// regardless of the result you MUST interrupt readLine task
// otherwise it might run forever
// *** if it is already done nothing bad will happen
//
readLine.cancel( true );
}
}
}
)
{
//
// you may even protect this task from being accidentally interrupted by your users:
// in fact it is not their responsibility
//
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
};
Executor executor = Executors.newCachedThreadPool();
// 3. execute both
executor.execute( readLine );
executor.execute( timedReadLine );
// 4. ...and here comes one of your users who can wait for only a second
try {
String answer = timedReadLine.get(1, TimeUnit.SECONDS);
//
// finally user got his (her) answer
//
} catch (InterruptedException e) {
//
// someone interrupted this thread while it was blocked in timedReadLine.get(1, TimeUnit.SECONDS)
//
} catch (ExecutionException e) {
//
// e.getCause() probably is an instance of IOException due to I/O failure
//
} catch (TimeoutException e) {
//
// it wasn't possible to accomplish socketIn.readLine() in 1 second
//
}
答案 2 :(得分:0)
我想出了一个解决方案:
answer = "";
try{
Thread d = new Thread(new Runnable() {
public void run() {
try {
answer = socketIn.readLine();
}
catch (IOException ex) {
System.out.println("IO exception occurred");
}
}
});
d.join(10000); //Not sure if this is superfluous or not, but it didn't seem to work without it.
d.start();
i = 0;
while (true){
if (i == 10000){
if (d.isAlive()) throw InterruptedException;
}
if (answer.equals("")){
Thread.sleep(1);
}
else{
break;
}
i++;
}
//This essentially acts as Thread.sleep(10000), but the way I
//implemented it, it checks to see if answer is modified or not every
//.001 seconds. It will run for just over 10 seconds because of these checks.
//The number in Thread.sleep could probably be higher, as it is
//unnecessary to check so frequently and it will make the code more efficient
//Once it hits 10000, it throws an exception to move to the catch block below
//where the catch block returns everything to its original state and
//returns the client to the beginning
}
catch (Exception e){
socketOut.println("Timeout Occurred. Returning you to the beginning...");
socketOut.flush();
pointer = tree.root;
//reset class members to their original state
return;
}
感谢您的关注,Brian Roach。你的帖子很有用,但我不小心省略了一些关键信息。我将来会尽量小心。