《java并发编程实战......读后感》

第一章:分布式Java应用

线程是Java语言不可避免的特性,它把复杂,异步的代码转换为更简单,更直观的代码,从而简化复杂系统的开发。线程是控制和利用多核CPU计算能力的最简单的方式。

线程是系统调度器的基本单位。

线程在GUI应用程序中很重要,可以用来改进用户接口的响应性,并且在服务器应用中,用于提高资源的利用率和吞吐量。

网络通信:

  * TCP/IP
  * UDP/IP
  * Multicast

Io:

  * BIO

  * NIO

  * AIO

分布式Java应用,两种典型发方法:

1.基于消息方式实现系统间的通信

2.基于远程调用方式实现系统间的通信

常用的实现系统间的通信协议有:TCP/IP & UDP/IP 协议。

TCP/IP协议:是一种可靠的网络传输协议,TCP/IP 要求双方首先建立连接,之后再进行数据传输。TCP/IP 负责保证数据传输的可靠性,包括数据的可到达,到达的顺序等。

缺点:TCP/IP 要保证连接和数据的传输可靠性,因此性能上差一些。

UDP/IP协议:是一种不保证数据一定到达的网络数据传输协议。UDP/IP 并不直接给通信的双方建立连接,而是发送到网络上进行传递。由于UDP/IP 不建立连接,并且不能保证数据传输的可靠,因此性能上要好些。

缺点:UDP/IP 不能保证数据到达的可靠性以及顺序可能会乱序。

TCP/IP & UDP/IP 协议 都可以用作数据的传输,但完成系统间的通信,需要对数据进行数据。例如读取和写入。按照POSIX 标准分为同步IO和异步IO两种,

同步IO : BIO (blocking io)  和 NIO (non-blocking io)。

从程序角度:BIO :当发起 IO 的读或写,均为阻塞方式,只有当程序读取到了流或将流写入操作系统后,才会释放资源。

基于事件驱动思想:NIO ,实现上通常采用reactor 模式。当发起IO 的读或写操作,是非阻塞的; 当socket 有流可读或可写入socket 时,操作系统会相应的通知应用程序进行处理,应用再将流读取到缓冲区或写入操作系统。

网络IO 操作动作主要有:连接建立,流读取和流写入三种事件。Linux 2.6以后采用epoll 实现NIO。

AIO 是异步IO 方式,基于事件驱动思想,实现上通常采用Proactor 模式。当进行读写操作时,只需要直接调用API 的 read 或 write

并发的原因:
1.公平性
2.便利性
3.资源利用率

线程也被称为轻量级的进程,线程是操作系统中的基本单位。

线程可以有效的降低程序的开发和维护成本,提升复杂应用程序的性能。

降低代码复杂度,使代码更容易编写,阅读和维护。

应用程序中,线程可以提高用户界面的响应灵敏度

服务器应用程序中,可以提升资源利用率以及系统吞吐率。

对程序员的技术要求高

2.安全性问题

3.活跃性问题:在开发并发代码时,一定要注意线程安全性是不可破坏的。

 注意:线程还会导致一些在单线程程序中不会出现的问题。

4.性能问题:线程带来不同程度的运行时开销。在多线程程序中,当线程调度器临时挂起活跃线程并转而运行另一个线程时,就会频繁出现上下文切换操作,这种操作将会带来极大的开销;保存和恢复执行上下文,丢失局部性,并且CPU 时间将更多的花在线程调度而不是线程运行上。当线程共享数据时,必须使用同步机制。而这些机制通常会抑制某些编译器优化,使内存缓存区中的数据无效,以及增加共享内存总线的同步流量。

5.线程无处不在:程序中没有显示的创建线程,但框架中仍可能会创建线程。例如AWT(abstract window toolkit 抽象窗口工具库) 和swing 。servlet 和 RMI (remote method invocation),都会创建线程池并调用这些线程中的方法。

线程不安全实例:

Private int value;

Private int getValue(){{

Return value ++;

}

UnsafeSequence 类中说明的是一种常见的并发安全问题,称为竞态条件(race condition)。在多线程下,getValue是否返回唯一值,取决于运行时对线程中操作的交替执行方式。

由于多个线程要共享相同的地址空间,并且是并发运行,因此他们会访问或修改其他线程正在使用的变量。

线程安全实例:

Private int value;

Private synchronized int getValue(){{

Return value ++;

}

Timer ,timer 类的作用是使任务在稍后的时刻运行,或运行一次,或周期性的运行。引入timer 会使串行程序变得复杂,因为timertask 将在timer 管理的线程中执行,而不是由应用程序来管理。如果某个timertask 访问了应用程序中其他线程访问的数据,那么不仅timertask 需要以线程安全的方式来访问数据,其他类也必须采用线程安全的方式来访问该数据。

Servlet 和 JSP ,servlet 框架用于部署网页应用程序以及分发来自HTTP客户端的请求,到达服务器的请求可能会通过一个过滤器链被分发到正确的servlet 或JSP,每个servlet 都表示一个程序逻辑组件,在高吞吐率的网站中,多个客户端可能会同时请求同一个servlet 的服务,所以servlet 需要是线程安全的。

RMI 远程方法调用,使代码能够调用在其他JVM 中运行的对象,当通过调用某个远程方法时,传递的方法参数必须被打包(列集)到一个字节流中,通过网络传输给远程JVM,然后由远程JVM拆包并传递给远程方法。所以也必须线程安全。

第二章:线程安全性。

可变:变量的值在其生命周期内可以发生变化。

共享:多个线程可以同时访问。一个对象是否需要线程安全,取决于是否被多个线程访问。要使对象是线程安全的,需要采用同步机制来协同对对象可变状态的访问。

当多个线程访问某个状态变量并且其中一个线程执行写入操作时,必须采用同步机制来协同这些线程对变量的访问,Java 中主要同步机制是synchronized ,它提供了一种独占的加锁方式,还包括volatile 类型的变量,显式锁explicit lock 以及原子变量。

无状态对象一定是线程安全的。

原子性:

竞态条件 race condition :存在多个竞态条件,从而结果变得不可靠,当某个计算正确性取决于多个线程的交替执行时序是,那么就会发生竞态矫健。【比如发布和查看发布版本】,最常见的竞态条件就是先检查后执行:check-then -action。

不安全的:

private Singleton instance = null;

Public Singleton getInstance (){

  if(instance == null){

    Instance = new Singleton();

    Return instance;

  }

}

安全的:

public class Counting implements Servlet{

  Private final AtomicLong value = new AtomicLong(0);

  Public long getValue(){

   Return value.get();

  }

 Public void service (ServletRequest req,ServletResponse resp){

 Value.incrementAndGet();

 }

}

内置锁:Java 提供了一种内置锁机制来支持原子性,同步代码块 synchronized block。

volatile 变量: Java 提供了一种稍弱的同步机制:volatile 变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile 类型后,编译器与运行时都会注意到这个变量是共享的。

在访问volatile 变量时不会执行加锁操作,因此就不会使执行线程阻塞,所以volatile 是比synchronized 更轻量级的同步机制。volatile 变量可见性对线程。

加锁机制既可以确保可见性又可以确保包原子性,而volatile 变量只能确保可见性。

volatile 使用场景:

1.对变量的写入操作不依赖变量的当前值,或者能够确保只有单个线程更新变量的值。

2.该变量不会与其他状态变量一起纳入不变性的条件中。

3.在访问变量时不需要加锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值