并发编程

 DougLea:《Concurrent Programming in Java:Design Principles and Patterns》

 

1、In Action

(1)执行的可能路径

Java代码会变成字节码指令。

对于指令系列中有N个指令和T个线程,没有循环或条件分支的简单情况,总的执行路径数量等于(NT)!    /   (N!)的T次幂

 

根据java内存模型,32位值的赋值操作是不可中断的。如 int a = 2;

根据JVM规约,64位值的赋值需要两次32位赋值。

 

框架——每个方法调用都需要一个框架。该框架包括返回地址、传入方法的参数,以及方法中定义的本地变量。这是定义一个调用堆栈的标准技术。现代编程语言用来实现基本函数调用和递归调用。

本地变量——方法作用范围内定义的每个变量。所有非静态方法至少有一个变量this,代表当前对象,即接收导致方法调用的(当前线程内)大多数最新消息的对象。

运算对象栈——java虚拟机中的许多指令都有参数。运算对象栈是放置参数的地方。

 

操作对象都处理对于方法而言是本地的信息。故多个线程之间并无冲突。

 

理解线程之间如何相互干涉的,并不一定要精通字节码。有必要尽量理解内存模型,明白什么是安全的,什么是不安全的。

必须要知道:

a、什么地方有共享对象/值;

b、哪些代码会导致并发读/写问题;

c、如何防止这种并发问题发生。

 

(2)Executor框架

Executor框架支持利用线程池进行复杂的执行。Executor框架将线程放到池中,自动调整其大小,并在必要时重建线程。它支持future,一种通用的并发编程构造。Executor能与实现了Runnable的类协同工作,也能与实现了Callable接口的类协同工作。Callback看来就像是Runnable,但它能返回一个结果。

 

(3)

 

2、TIPS

(1)要保持并发系统整洁,应该将线程管理代码约束于少数几处控制良好的地方。

为每个职责创建单独的类

 

(2)非锁定的解决方案

java5虚拟机利用现代处理器支持可靠、非锁定更新的设计优点。

如java5有一系列的新类,如AtomicBoolean、AtomicInteger、AtomicReference等。可以使用非锁定的手段。

 

现代处理器有比较交换(CAS)操作,这种操作类似于数据库中的乐观锁定,而其同步版本则类似于保守锁定。

 

关键字synchronized总是要求上锁,即使第二个线程并不更新同一值时也是如此。尽管这种固有锁的性能一直在提升,但代价仍然昂贵。

 

非上锁的版本假定多个线程通常并不频繁修改同一个值。

CAS的操作是原子的。逻辑上是这样:当某个方法试图更新一个共享变量,CAS操作就会验证要赋值的变量是否保有上一次的已知值。若是,就修改变量值。若不是,则不会碰变量,因为另一个线程正在试图更新变量值。要更新数据的方法(通过CAS操作)查看是否修改并持续尝试。

 

(3)非线程安全类

a、数据库连接

b、java.util中的容器

c、servlet

线程安全的集合:java.util.concurrent中的集合,如ConcurrentHashMap。

 

(4)出现错误时,有两种解决方法

a、基于客户代码的锁定

b、基于服务端的锁定(建议)——修改服务端代码解决问题,同时也修改了客户代码。若无法修改服务端代码,可以使用适配器模式修改API,添加锁定。

更好的方法是使用线程安全的集合和扩展接口

 

(5)死锁

死锁的发生需要4个条件:

a、互斥:当多个线程需要使用同一资源,而此资源无法在同一时间为多个线程所用

b、上锁及等待:当某个线程获取一个资源,在获取到其他全部所需资源并完成其工作之前,不会释放这个资源;

c、无抢先机制:线程无法从其他线程处夺取资源。一个线程持有资源时,其它线程获得这个资源的唯一手段就是等待该线程释放资源;

d、循环等待

这4个条件都是死锁必需的。只要其中一个不满足,死锁就不会发生。

 

避免死锁的一种策略是规避互斥条件。可以使用允许同时使用的资源,如AtomicInteger

线程1同时需要资源1和资源2、线程2同时需要资源2和资源1,只要强制线程1和线程2以同样次序分配资源,循环等待就不会发生。

 

有许多避免死锁的方法,有些会导致饥饿,另外一些会导致对CPU能力的大量耗费和降低响应率。

 

将解决方案中与线程相关的部分分割出来,再加以调整和试验。

 

小心记录在何种条件下测试失败

 

测试线程代码的工具支持:

IBM提供ConTest的工具,它能对类进行装置,令非线程安全代码更有可能失败。

 

(6)

 

3、PS

(1)系统在什么地方耗费时间

a、I/O——使用套接字、连接到数据库、等待虚拟内存交换等;

b、处理器——数值计算、正则表达式处理、垃圾回收等。

若代码运行速度主要和处理器相关,增加处理器硬件就能提升吞吐量。CPU运算周期是有上限的,只是增加线程的话并不会提升受处理器限制的代码的速度

若吞吐量与IO有关,则并发编程能提升运行效率。当系统的某个部分在等待IO,另一部分就可以利用等待的时间处理其他事,从而有效利用了CPU能力。

 

IO操作不耗费处理器能力

 

(2)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值