Java多线程1:为什么要使用多线程——学习方腾飞Java并发编程的艺术

为什么要使用多线程

简单来讲,就是为了程序运行的更快

1、发挥多处理器的强大能力(见http://www.cnblogs.com/xrq730/p/4850883.html

现在,多处理器系统正日益盛行,并且价格不断降低,即时在低端服务器和中断桌面系统中,通常也会采用多个处理器,这种趋势还在进一步加快,因为通过提高时钟频率来提升性能已变得越来越困难,处理器生产厂商都开始转而在单个芯片上放置多个处理器核。试想,如果只有单个线程,双核处理器系统上程序只能使用一半的CPU资源,拥有100个处理器的系统上将有99%的资源无法使用。多线程程序则可以同时在多个处理器上执行,如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率。

2、在单处理器系统上获得更高的吞吐率

如果程序是单线程的,那么当程序等待某个同步I/O操作完成时,处理器将处于空闲状态。而在多线程程序中,如果一个线程在等待I/O操作完成,另一个线程可以继续运行,使得程序能在I/O阻塞期间继续运行。

3、建模的简单性

通过使用线程,可以将复杂并且异步的工作流进一步分解为一组简单并且同步的工作流,每个工作流在一个单独的线程中运行,并在特定的同步位置进行交互。我们可以通过一些现有框架来实现上述目标,例如Servlet和RMI,框架负责解决一些细节问题,例如请求管理、线程创建、负载平衡,并在正确的时候将请求分发给正确的应用程序组件。编写Servlet的开发人员不需要了解多少请求在同一时刻要被处理,也不需要了解套接字的输入流或输出流是否被阻塞,当调用Servlet的service方法来响应Web请求时,可以以同步的方式来处理这个请求,就好像它是一个单线程程序。

4、异步事件的简化处理

服务器应用程序在接受多个来自远程客户端的套接字连接请求时,如果为每个连接都分配其各自的线程并且使用同步I/O,那么就会降低这类程序的开发难度。如果某个应用程序对套接字执行读操作而此时还没有数据到来,那么这个读操作将一直阻塞,直到有数据到达。在单线程应用程序中,这不仅意味着在处理请求的过程中将停顿,而且还意味着在这个线程被阻塞期间,对所有请求的处理都将停顿。为了避免这个问题,单线程服务器应用程序必须使用非阻塞I/O,但是这种I/O的复杂性要远远高于同步I/O,并且很容易出错。然而,如果每个请求都拥有自己的处理线程,那么在处理某个请求时发生的阻塞将不会影响其他请求的处理。

多线程的挑战

1.上下文切换

2.死锁

3.资源限制

那么多线程一定快吗(上下文切换)?

不一定

当并发数不超过百万次时,并行的速度会比串行速度慢,原因就是线程有创建和上下文切换的开销,如何减少上下文切换呢

1.无锁并发编程

例如ConcurrentHashMap,可以将数据的ID按hash分成不同的段(segment),然后分段加锁,不同段的操作无需加锁,而不是每次操作都锁住全部

2.CAS算法

使用JAVA的Atomic包的CAS操作,无需加锁

3.使用最小线程

避免建立不需要的线程,根据需要建立

4.使用协程

在单线程中实现多任务调度,并在但线程中维持多个任务的切换

死锁

死锁就是,当一个线程永远地持有一个锁,并且其他线程都尝试去获得这个锁时,那么它们将永远被阻塞,这个我们都知道。如果线程A持有锁L并且想获得锁M,线程B持有锁M并且想获得锁L,那么这两个线程将永远等待下去,这种情况就是最简单的死锁形式。

如何避免死锁呢?

1.避免一个线程同时获得多个锁

2.尽量保证每个锁只占用一个资源

3.尝试使用定时锁

4.对于数据库锁,加锁解锁必须在一个数据库连接中,否则会出现解锁失败的情况

资源限制

并发编程中,程序的运行受限于计算机硬件软件资源的限制,如服务器带宽2M/s,某个资源下载速度1M/s,系统启动10个线程,速度并不会10M/s,所以并发编程时,要考虑这种情况。

怎么解决呢?硬件上当然可以让程序在多机上运行,如使用OPDS,hadoop搭建自己的集群,不同机器处理不同的数据,软件上,考虑使用资源池将资源复用,比如数据库连接池。

总之,多线程技术有优点也有挑战,但是值得我们去深入研究并应用多线程。

猜你喜欢

转载自blog.csdn.net/qq_22798455/article/details/81217306