ExecutorService 的execute 和thread.run in 运行 threads concurrently in Java有什么区别?

What the difference between ExecutorService's execute and thread.run in running threads concurrently in Java?

我是 java 中的这种并发编程的新手,并提出了以下场景,我对何时使用哪个感到困惑。

场景 1: 在下面的代码中,我试图通过在 GPSService class 上调用 .start() 来 运行 线程这是一个 Runnable 实现。

int clientNumber = 0;
ServerSocket listener = new ServerSocket(port);

while (true) {
            new GPSService(listener.accept(), clientNumber++, serverUrl).start();
} 

场景 2: 在下面的代码中,我尝试使用 ExecutorService class 运行 线程,如图所示

int clientNumber = 0;
ServerSocket listener = new ServerSocket(port);
while(true) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(new GPSService(listener.accept(), client++, serverUrl));

        executor.shutdown();
        while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
            // Threads are still running
            System.out.println("Thread is still running");
        }
        // All threads are completed
        System.out.println("\nThread completed it's execution and terminated successfully\n");              
}

我的问题是
在并发编程中调用线程的最佳实践是什么?
当我第一次或第二次使用时,我最终会得到什么结果(麻烦)?
注意:我一直面临第一种情况的问题,程序每隔几天就会挂起。那么,当我使用第一种方法时,这个问题是 related/expected 吗?
任何 good/helpful 回答将不胜感激 :) 谢谢

除了在场景 2 中管理线程终止外,您发布的两个场景没有太大区别;您总是为每个传入请求创建一个新线程。如果您想使用 ThreadPool,我的建议是不要为每个请求创建一个,而是为每个服务器创建一个并重用线程。类似于:

public class YourClass {

//in init method or constructor 
ExecutorService executor = Executors....;// choose from newCachedThreadPool() or newFixedThreadPool(int nThreads) or some custom option


int clientNumber = 0;
ServerSocket listener = new ServerSocket(port);
while(true) {

    executor.execute(new GPSService(listener.accept(), client++, serverUrl));

}

这将允许您使用线程池并控制为您的服务器使用的线程数。如果您想使用执行器,这是首选方法。

对于服务器池,您需要决定池中有多少个线程;你有不同的选择,但你可以开始或使用固定数量或线程或尝试使用非繁忙线程的池,如果所有线程都忙,它会创建一个新线程(newCachedThreadPool())。要分配的线程数取决于许多因素:并发请求数及其持续时间。您的服务器端代码花费的时间越多,您就越需要额外的线程。如果您的服务器端代码速度非常快,则池很可能会回收已分配的线程(因为请求不会在同一时刻全部到达)。

比如说你在一秒钟内有10个请求,每个请求持续0.2秒;如果请求到达 0、0.1、0.2、0.3、0.4、0.5、.. 秒的一部分(例如 23/06/2015 7:16:00:00、23/06/2015 7:16:00:01、23/ 06/2015 7:16:00:02) 你只需要三个线程,因为 0.3 的请求可以由服务第一个请求的线程(0 处的那个)执行,依此类推(0.4 的请求可以重用线程用于 0.1 时的请求)。三个线程管理十个请求。

我建议您(如果您还没有阅读的话)阅读 Java 并发实践(任务执行是第 6 章);这是一本关于如何在 Java.

中构建并发应用程序的优秀书籍

来自 Oracle documentation 来自 Executors

public static ExecutorService newCachedThreadPool()

Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks.

Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache.

Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors.

public static ExecutorService newFixedThreadPool(int nThreads)

Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available.

If any thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks. The threads in the pool will exist until it is explicitly shutdown.

@Giovanni 是说您不必向 newCachedThreadPool 提供线程数,这与 newFixedThreadPool() 不同,后者必须传递最大值限制 ThreadPool 中的线程数。

但在这两者之间,newFixedThreadPool() 是首选。 newCachedThread Pool 可能会导致泄漏,并且由于无限制的性质,您可能会达到最大可用线程数。有些人认为这是一种邪恶。

看看相关的SE问题:

Why is an ExecutorService created via newCachedThreadPool evil?