您的位置:首页 > 编程语言 > Java开发

Java 多线程及线程池理论分析

2012-10-30 21:15 316 查看
    java提供了对多线程的支持,若对每个客户都分配一个新的工作线程,当工作线程与客户通信结束,这个线程则被销毁,这种方式的不足之处:

1.服务器创建和销毁工作线程的开销(包括所花费的时间和系统资源)很大。如果服务器需要与许多客户通信,并且与每隔客户的通信时间都很短,那么有可能服务器为客户创建新线程的开销比实际与客户通信的开销还要大。

2.除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。每个线程本身都会占用一定的内存,如果同时有大量客户连接服务器,就必须创建大量工作线程,它们消耗了大量的内存,可能导致系统的内存空间不足。

3.如果线程数目固定,并且每隔线程都有很长的生命周期,那么线程切换也是相对固定的。如果频繁的创建和销毁线程,那么将导致频繁的切换线程。在这种情况下,线程之间的切换不再遵循系统的固定切换周期,切换线程的开销甚至比创建及销毁线程的开销还大。

线程池为线程生命周期开销问题和系统资源不足问题提供了解决方案:优点
 * 1.减少了创建和销毁线程的次数,每个工作线程都可以一直被重用,能执行多个任务

 * 2.可以根据系统的承载能力,方便的调整线程池中线程的数目,防止因消耗过量资源使系统崩溃

使用线程池的注意事项:

     虽然线程池能大大提高服务器的并发性能,但使用它也会存在一定的风险。与所有多线程应用程序一样,用线程池构建的应用程序容易产生各种并发问题,如对共享资源的竞争和死锁。此外,如果线程池本身的实现不健壮,或者没有合理地使用线程池,还容易导致与线程池有关的死锁、系统资源不足和线程泄漏等问题。

1.死锁

任何多线程应用程序都有死锁风险。造成死锁的最简单的情形是,线程A持有对象X的锁,并且在等待对象Y的锁,而线程B持有对象Y的锁,并且在等待对象X的锁。线程A与B都不释放自己持有的锁,并且等待对方的锁,这就导致两个线程永远等待下去,死锁就这样产生了。

不但任何多线程程序都有死锁的风险而且线程池还会导致另外一种死锁。在这种情况下,假定线程池中所有工作线程都在执行各自任务时被阻塞,它们都在等待某个任务A的执行结果。而任务A依然在工作队列中,由于没有空闲线程,使得任务A一直不能被执行。这使得线程池中的所有的工作线程都永远阻塞下去,死锁就这样产生了。

2.系统资源不足

如果线程池中的线程数目非常多,这些线程会消耗包括内存和其他系统资源在内的大量资源,从而严重影响系统性能。

3.并发错误

线程池的工作队列依靠wait()和notify()方法来使工作线程及时取得任务,但这两个方法都难于使用。如果程序不正确,可能会丢失通知,导致工作线程一直保持空闲状态,无视工作队列中需要处理的任务。因此使用这些方法时,必须格外小心,最好使用现有的、比较成熟的线程池。例如,直接使用java.util.concurrent包中的线程池类。

4.线程泄漏

使用线程池的一个严重的风险是线程泄漏。对于工作线程数目固定的线程池,如果工作线程在执行任务时抛出RuntimeException或Error,并且这些异常或错误没有被捕获,那么这个工作线程就会异常终止,使得线程池永远失去一个工作线程。如果所有的工作线程都异常终止,线程池就最终变为空,没有任何可用的工作线程来处理任务。

导致线程泄露的另一种情形是,工作线程在执行一个任务时被阻塞,如等待用户输入数据,但由于用户一直不输入数据(可能因为用户走开了),导致这个工作线程一直被阻塞。这样的线程名存实亡。假如线程池中所有的工作线程都处于这样的阻塞状态,那么线程池就无法处理新加入的任务了。

5.任务过载

当工作队列中有大量排队等候执行的任务时,这些任务本身可能会消耗太多的系统资源而引起系统资源缺乏。

综上所述,线程池可能带来种种风险,为了尽可能避免它们,使用线程池时需要遵循以下原则。

1).如果任务A在执行过程中需要同步等待任务B的执行结果,那么任务A不适合加入到线程池的工作队列中,否则,可能导致死锁。

2).如果执行某个任务时可能会阻塞,并且是长时间的阻塞,则应该设置超时时间,避免工作线程永久的阻塞下去而导致线程泄露。在服务器程序中,当线程等待客户连接,或者等待客户发送的数据时,都可能会阻塞。

设定超时时间:

   对于服务器端ServerSocket,调用ServerSocket的setSoTimeout(int timeout)方法,设定等待客户连接的超时时间。

   对于与客户连接的Socket,调用该Socket的setSoTimeout(int timeout)方法,设定等待客户发送数据的超时时间。

3).避免任务过载。服务器应根据系统的承载能力,限制客户并发连接的数目。当客户并发连接的数目超过了限制值,服务器可以拒绝连接请求,并用好的告知用好:服务器正忙,请稍后再试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程 线程池 Java