Java - 在没有阻塞主线程的情况下停止thead

时间:2017-06-15 08:16:55

标签: java multithreading

我正在创建一个接收HTTP请求的Java应用程序。对于每个进来的请求,我启动一个新线程,在该线程中我正在读取请求并执行必要的操作。但是,我想阻止用户执行“慢速Loris攻击”,因此我在考虑为线程提供maxTime值。如果线程花费的时间超过maxTime,它将终止,无论如何。因此它也会阻止慢速连接,这是问题。

但是,我不知道这样做的正确方法是什么。我尝试了下面的代码,但这段代码阻止了我的主线程。我正在寻找一种方法来做类似这样的事情,而不会阻塞主线程。

代码:

/**
 * Executor which is used for threadpools.
 */
private ExecutorService executor;

/**
 * Constructor for the class RequestReceiver.
 * Initializes fields.
 */
public RequestReceiver() {
    this.executor = Executors.newFixedThreadPool(200);
}

@Override
public void run() {
    try {
        this.serverSocket = new ServerSocket(port);
    } catch (IOException ex) {
        Logger.getInstance().logText("Could not start server on port: " + port);
        return;
    }

    Logger.getInstance().logText("Server running at port: " + port);

    try {
        while (shouldContinue) {
            Socket client = serverSocket.accept();
            HTTPRequestHandler handler = new HTTPRequestHandler(client);
            Thread t = new Thread(handler);
            executor.submit(t).get(10, TimeUnit.SECONDS); //This line is blocking
        }
    } catch (IOException ex) {
        Logger.getInstance().logText("Server is shutdown");
    } catch (InterruptedException | ExecutionException | TimeoutException ex) {
        Logger.getInstance().logText("Thread took too long, it's shutdown");
    }
}

2 个答案:

答案 0 :(得分:1)

对您的示例进行的最少更改可以为您提供类似于您想要的内容,即提交新任务。

Socket client = serverSocket.accept();
HTTPRequestHandler handler = new HTTPRequestHandler(client);
Future f = executor.submit(handler);
executor.submit(()->{
    try{
        f.get(10, TimeUnit.SECONDS);
    } catch(TimeoutException to){
        //timeout happened, this will cancel/interrupt the task.
        f.cancel(true);
    } catch(Exception e){
        throw new RuntimeException(e);
        //something else went wrong...
    }
});

这可以工作,但它会阻止一个额外的线程等待get调用。您还需要在HTTPRequestHandler代码中处理中断。

另一种方法是使用ScheduledExecutorService

答案 1 :(得分:0)

您的方法存在一些问题:

  

我正在创建一个接收HTTP请求的Java应用程序。对于每个进来的请求,我启动一个新线程,在该线程中我正在读取请求并执行必要的操作。

这是耗尽内存或其他资源的可靠方法。相反,在servlet容器(tomcat,jetty)中运行应用程序,让它为您处理多线程。只需确保处理请求的代码是“线程安全的”,因为它将由多个线程同时调用。

如果您必须使用ServerSocket,请使用具有固定线程数的ExecutorService。 (绝不使用无限数量的线程)

  

但是,我想阻止用户执行“慢速Loris攻击”

要防止slowloris攻击,您应该在http服务器(例如Apache)后面运行您的应用程序,并确保安装相应的安全模块。例如:http://www.techrepublic.com/blog/smb-technologist/secure-your-apache-server-from-ddos-slowloris-and-dns-injection-attacks/

  

我在考虑为线程提供maxTime值。如果线程花费的时间超过maxTime,它将终止,无论如何。

这不是一个好主意。通常,当您收到HTTP请求时,控制器(处理请求的代码)必须尽快回复,但执行此操作的方法是优化请求的处理(例如,不要执行操作在处理http请求时花费太长时间)。 如果您的处理时间很快,但从客户端的角度来看,服务器没有响应,那么您应该考虑分发您的应用程序(将许多服务器实例置于负载均衡器之后)