java 并发编程的优势与危险

2016-07-18 08:58:47   最后更新: 2016-07-30 23:21:26   访问数量:754




此前,我们曾经介绍过 linux 下的进程和线程:

线程的基本概念

本篇日志中,我们来介绍一下 java 的线程并发模型,主要来看看 java 的线程有哪些优势与潜在的危险

 

多线程并发编程的优势是显而易见的:

  1. 发挥多处理器的强大能力
  2. 简化任务模型
  3. 简化异步事件的处理,降低开发难度
  4. 任务的快速响应

 

正如此前的日志中详细介绍过的 linux 线程中复杂的安全性问题,java 线程安全性问题也是同样复杂

多个线程的执行顺序是不可预测的,因此可能会产生奇怪的结果

 

public class UnsafeSequence { private int value; public int getNext() { return value++; } }

 

上面的代码是非线程安全的,尽管这个类中仅仅包含的 getNext 方法看上去非常简单,但它包含了三个操作:

  1. 读取 value
  2. 将 value + 1
  3. 将结果写入 value

在多线程并发的情况下,第一个线程还没有执行到第三步时,第二个线程读取 value,那么两个线程将读取到同一个 value 值,因此他们通过加一操作会得到相同的结果

最终,之行结束以后,尽管有两个线程执行了 +1 操作,但是结果却仅仅加了一次

这就是一种常见的并发问题:竞争条件

fork 与竞争条件

 

如何来解决这个问题呢?幸运的是,java 提供了各种同步机制来协同并发访问

public class Sequence { @GuardedBy("this") private int Value; public synchronized int getNext() { return Value++; } }

 

@GuardedBy 注解告诉维护着这个类受对象内部锁保护

而 synchronized 关键字标识了同步代码块,他让 getNext 方法只能同时被一个线程执行,当一个线程在这个代码块中时,其他即将进入的线程将阻塞

 

所谓的活跃性问题指的是某件正确的事情最终没有发生

事实上,非并发环境中也常常会发生活跃性问题,那就是被人们熟知的死循环,致使循环之后的正确的代码永远无法得到执行

而在并发环境中,死锁、饥饿、活锁等问题常常是难以预料和分析的,他们让某个线程永远的等待下去,从而进入活跃性问题

然而,由于并发环境难以构造,问题总是不能够复现,这更加加重了问题的复杂性和严重性

 

多线程并发意味着 CPU 调度负担的增加,同时,频繁的上下文切换在增加 CPU 时间的同时也带来了内存的大量开销

这也是需要谨慎考虑的一个问题

 






技术帖      技术分享      线程      多线程      竞争条件      thread      线程同步      并发      java      concurrent     


京ICP备15018585号