《Java并发编程实践——第一章(介绍)、第二章(线程安全)》

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011067966/article/details/84037684

介绍##

1.1 并发的简短历史

相同的关注点(资源利用,公平和方便) 不仅促进了进程的发展,也促进了线程的发展、
线程允许程序控制流的多重分支同时存在于一个进程。它们共享进程范围内的资源,比如内存和文件句柄,但是线程有自己的程序计数器、栈、和本地变量。

1.2 线程的优点

提高性能,降低程序复杂度。在服务器应用中,提高资源利用率和吞吐量。

1.3 线程的风险

1.3.1 安全危险

在这里插入图片描述
竞争条件:当被多线程调用时,getNext是否能返回不重复的值。
因为线程共享相同的内存地址空间,且并发地运行,它可能访问或修改其他线程正在使用的变量。

1.3 线程无处不在

定时器:Timer访问的数据必须是线程安全的。
Servlet:Servlet可能会访问共享的对象(Session等),必须是线程安全
远程方法调用:RMI使你能够调用在另外一个JVM上运行的对象的方法。

线程安全##

编写线程安全的代码,本质上就是对状态的方法,而且通常都是共享的、可变的状态。

状态:一个对象的状态就是它的数据,存储在状态变量,比如实例或静态域。
包含了任何会对它外部可见行为产生影响的数据。
共享:指一个变量可以被多个线程访问。
可变:指变量在其生命周期内可以改变。

2.1 什么是线程安全性

在这里插入图片描述

2.1.1 无状态的servlet

无状态对象永远是线程安全的。

不包含域,也没有引用其他类的域

2.2 原子性

原子性:不能作为单独的、不可分割的操作。
count++:包含了三次操作,读-改-写。

2.2.1 竞争条件

检查再运行:使用潜在的过期观察值来做决策或执行计算。

2.2.2 惰性初始化中的竞争条件

检查再运行的常见用法是惰性初始化:
在这里插入图片描述
竞争条件并不总是失败的,还需要某些特殊的分时。

2.2.3 复合操作

检查再运行和读-改-写的操作看成复合操作:操作必须原子地执行。
可以使用已有的线程安全类:aromic包。

2.3 锁

为了保护状态的一致性,要在单一的原子操作中更新相互关联的状态变量。

2.3.1 内部锁

内部锁:每个Java对象都可以隐式地扮演一个用于同步的锁的角色。
在这里插入图片描述

synchronized放的锁就是该方法所在的对象本身。

2.3.2 重进入

当一个线程请求其他线程已经占有的锁时,请求线程将被阻塞。
然后内部锁是可重进入的。
JVM会被每个锁关联一个请求计数,计数为0表示未被占有。
在这里插入图片描述
子类覆写了父类的synchronized类型的方法,如果没有可重入锁,看上去像死锁。

2.4 用锁来保护状态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5 活跃度和性能

在这里插入图片描述

service方法声明为synchronized,因此每次只能有一个线程执行它。这违背了Servlet的初衷:同时处理多个请求。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u011067966/article/details/84037684