2015-06-20 69 views
6

我是新来的这个并发编程在Java中,并提出了以下情况下,我越来越混乱使用时。

方案1:在下面的代码我试图通过调用。开始()上GPSService类,这是一个Runnable实施运行的线程。在Java中同时运行线程中ExecutorService的执行和thread.run之间的区别是什么?

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

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

方案2:在下面的代码,我尝试使用的ExecutorService类运行的线程,如图

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");    
} 

我的问题是
这是调用线程的最佳实践并发编程?
什么是结果(麻烦)当我第一次或第二次使用时,我会最终结束?
注意:我一直在面对第一种情况,即每隔几天后程序被吊死的问题。那么,当我使用第一种方法时,这个问题是否与预期相关?
任何好的/有益的答案将不胜感激:)谢谢

+0

可能重复http://stackoverflow.com/questions/2049948/thread-pool-vs-thread -spawning) –

+0

@NarendraPathai我更具体到我的问题,如果是的话,你怎么能把它标记为重复? –

+0

@NarendraPathai我刚刚提到过,只是为了澄清FirstScenario是否有可能导致此类问题。为了您的理解,我没有要求解决这个悬而未决的问题。并感谢您的参考 –

回答

3

您发布的两种情况没有什么大的区别,除了在Scenario2中管理线程终止;您总是为每个传入请求创建一个新线程。如果你想使用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)); 

} 

这将允许您使用线程池并控制要为您的服务器使用多少个线程。如果你想使用Executor,这是首选的方法。

使用服务器池,您需要确定池中有多少个线程;您有不同的选择,但您可以启动或使用固定数量或线程,或者尝试使用非忙线程的池,并且如果所有线程都忙,则会创建一个新线程(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中构建并发应用程序的优秀书籍。

+0

因此,如果我使用newCachedThreadPool()或newFixedThreadPool(int nThreads),因为我从数百个客户端每四秒钟获取数据,如果我不会以任何问题结束为每个客户使用单线程? –

+1

如果您设法正确调整池的大小,使用newCachedThreadPool()不会有任何问题,甚至不会在线程数上设置上限 – Giovanni

1

从Oracle documentationExecutors

public static ExecutorService newCachedThreadPool() 

创建一个创建新线程需要的,但可用时将重用以前构造的线程的线程池。这些池通常会提高执行许多短暂异步任务的程序的性能。

调用执行将重用以前构造的线程(如果可用)。如果没有现有线程可用,则会创建一个新线程并将其添加到池中。未使用六十秒的线程将被终止并从缓存中移除。

因此,保持闲置时间足够长的池不会消耗任何资源。请注意,使用ThreadPoolExecutor构造函数可以创建具有类似属性但具有不同细节的池(例如,超时参数)。

public static ExecutorService newFixedThreadPool(int nThreads) 

创建一个可重用不受限制的队列操作线程的固定数目的线程池。在任何时候,最多nThreads线程都将被激活处理任务。如果在所有线程处于活动状态时提交其他任务,则它们将在队列中等待,直到线程可用。

如果任何线程在关闭之前的执行期间由于失败而终止,那么如果执行后续任务需要新的线程将取代它。池中的线程将一直存在,直到它被明确关闭。

@Giovanni是说,你不必须提供的线程数来newCachedThreadPool不像newFixedThreadPool(),在那里你必须通过对线程池的线程数最高上限。

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

看一看相关SE问题:

Why is an ExecutorService created via newCachedThreadPool evil?

[线程池VS主题产卵(的
+0

使用newFixedThreadPool()时如何确定线程使用的数字。 – Jesse

+0

从Runtime.getRuntime()开始。availableProcessors() –

相关问题