-
线程的优势
降低成本,提高性能;
发挥多处理器能力;
建模的简单性
异步时间的简单处理;
响应灵敏的用户界面;
-
线程的风险
安全性问题:永远不发生糟糕的事情
@NotThreadSafe
public class UnsafeSequence
{
private int value;
/*返回一个唯一的数值*/
public int getNext()
{
value ++;
}
}
递增操作是分成三个独立的操作:
读取value
将value加1
将计算结果写入value
如上图,是不同线程之间一种交替执行情况,
执行时序从左到右,
每行表示一个线程的执行操作,
每个方形图表示一个操作,
竞态条件(Race Condition):是指两个或多个进程/线程对共享的数据进行读或写的操作时,最终的结果取决于这些进程/线程中操作的交替执行顺序。
@ThreadSafe
public class UnsafeSequence
{
@GuardedBy("this") private int value;
public synchronized int getNext()
{
value ++;
}
}
活跃性问题:某件正确的事情最终会发生
单线程活跃性问题:无意中造成的无限循环,从而使循环后的代码永远不会被执行。
多线程活跃性问题:如线程A等待线程B释放其持有的资源,而线程B永远都不释放该资源,那么A将永远等待下去。死锁,饥饿,活锁
性能问题:正确的事情尽快发生。
服务时间过长,响应不灵敏,吞吐率过低,资源消耗过高,可伸缩性低等
-
线程无处不在
框架中可能会创建线程,在这些线程中调用的代码需要是线程安全的。
JVM内部任务(如,垃圾收集,终结操作等)会创建后台线程。
SWing,AWT用户界面创建线程来管理用户界面事件,GUI应用程序有一个固有的属性是异步性,用户可以在任意时间选择菜单或者点击按钮,它们创建了一个单独的线程来处理用户出发的事件,并对界面进行更新。事件处理器如果访问了由其他线程同时访问的程序状态,那么这个事件处理器,以及访问这个状态的所有其他代码,都必须采用一种线程安全的方式来访问这个状态。
Timer创建线程来执行延迟任务:Timer在其管理的线程中执行TimerTask,如果TimerTask访问了其他线程访问的应用程序状态,那么,所有程序路径都必须以线程安全的方式访问这些应用程序状态。通常是把共享数据对象本身设计成线程安全的。
Servlet和JavaServerPage(JSP):Servlet框架用于部署网页应用程序以及分发来自HTTP客户端的请求。到达服务器的请求可能会通过一个过滤器链被分发到正确的Servlet或JSP。Servlet需要时线程安全的。
RMI 会创建线程池:调用RMI对象方法的地方可能创建线程。RMI对象可能在多个线程中被访问,需要保证RMI对象是线程安全的。
框架会回调应用程序的代码,将并发性引入到程序中,在代码中不可避免的访问应用程序状态,因此所有访问这些应用程序状态的代码路径都必须是线程安全的。