我有以下代码,它连接到服务器,发送请求,然后返回响应。
问题是,如果客户端无法连接到服务器,程序将永远无法通过这一部分
PayLoad payLoadFromServer = client.sendRequest();
我只是想知道防止程序冻结的最佳方法是什么,也就是说,如果客户端无法连接,我想在5秒后超时,并能够在程序中优雅地处理它。注意,我无法编辑客户端类。
public PayLoad queryServer() {
try (final Client client = new Client("127.0.0.1", "8080")) {
PayLoad payLoadFromServer = client.sendRequest();
return payLoadFromServer;
}
}
非常感谢!
您应该在Client
类中使用java.net.Socket的方法connect(SocketAddress endpoint,int timeout)。这是最好的解决方案,但也可能存在其他解决方案。
我试着快速尝试一下。为客户端类创建一个包装器对象,并使这个新对象可运行。
public class ClientWrapper implements Runnable {
private final String ip;
private final String port;
private Client client;
Lock lock = new ReentrantLock();
/**
* Creates a new instance of ClientWrapper.
*
* @param ip
* @param port
*/
public ClientWrapper(String ip, String port) {
this.ip = ip;
this.port = port;
}
public Lock getLock() {
return lock;
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
lock.lock();
client = new Client(ip, port);
lock.unlock();
}
//create a method to expose client or its methods.
}
现在使用这个对象的一个实例作为线程,如下所示。
import java.util.concurrent.TimeUnit;
/**
* @author rbhatt
*/
public class ClientCaller {
public static void main(String args[]) throws InterruptedException {
ClientWrapper clientWrapper = new ClientWrapper("127.0.0.1", "8080");
Thread t = new Thread(clientWrapper);
t.start();
boolean ret = clientWrapper.getLock().tryLock(250, TimeUnit.MILLISECONDS);
if (ret == false) {
System.out.println("can not acquire lock in 250 milliseconds, kill the thread.");
t.interrupt();
} else {
System.out.println("acquired lock in 250 milliseconds,release lock obtain client!");
clientWrapper.getLock().unlock();
}
}
}
正如您所看到的,您可以在调用者中控制您的超时,而我们无法获得锁,杀死了客户端包装线程。我已经使用了中断,您可以使用volatile
变量。您也可以使用executor service
和thread pools
等
注意:我写这段代码只是为了说明这个想法,可以通过多种不同的方式改进代码
我会在客户端代码中添加一个计时器,这样,如果在5秒内没有建立连接,套接字就会关闭。这对外部来说要困难得多。
如果您使用Socket连接到客户端,您可以提供一个SocketFactory,并为它创建的每个Socket设置timout。
换句话说,我可能会使用两个线程。第一个进行实际连接,第二个在第一个超时后触发中断。
这将需要一系列锁,一个用于防止在尝试连接之前发生超时,另一个用于等待尝试
最好使用Timer,这里是网络操作超时的好链接。用Java处理网络超时http://www.javacoffeebreak.com/articles/network_timeouts/
不是最好的主意,但这取决于您的项目逻辑和环境。您可以使用ExecutorService:包装您的方法
import java.util.concurrent.*;
private int threads = 10;
// overide thread count to prevent too many threads to be created
private ExecutorService executor = new ThreadPoolExecutor(0, threads,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
// if TimeOutException isthrown - then 5 secs is out
public PayLoad sendRequest(long timeout) throws InterruptedException, ExecutionException, TimeoutException {
return executor.submit(new Callable<PayLoad>() {
@Override
public PayLoad call() {
// your code implementation of client.sendRequest();
}
}).get(timeout, TimeUnit.SECONDS);
}
我在这里使用了10个线程的缓存线程池。唯一不好的是用另一个线程包装方法的每个调用。不要忘记关闭您的池实现。