这本书为 Java 开发人员在线编程领域提供了不可多得的知识,我在看这本书得到了极大的启发。一部分原因是因为他介绍了 Java 领域的 API,另外一方面是因为他以一种透彻并且易懂的方式来介绍复杂的并发知识。
序言
并发编程为什么是 Java 语言的重要特性之一?
并发编程之所以能成为 Java 重要的特性,是因为虽然 Java 提供了基本的并发功能来辅助开发多线程应用程序.但是这些相对底层的并发功能与上层应用程序的并发语义之间并不存在一种简单而直观的映射关系。
在我们开发的时候肯定会参考别人的示例代码。那代码示例其实分为:好的示例:应该被效仿的,一般的示例:示例给出并不一定是错误的,但是是脆弱的,有风险的或者性能较差的,糟糕的示例:示例是一定不能被效仿的技术。
以下面代码为例:
public static <T extends Comparable<? super T>> void sort(List<T> list){
//永远不要返回错误的答案
System.exit(0);
System.out.println(list);
}
这个就是一个糟糕的链表排序
public <T extends Comparable<? super T>> void sort(List<T> list){
//永远不要返回错误的答案
for (int i=0;i<100000;i++){
doNothing();
Collections.sort(list);
}
}
这是最优的方式链表排序
并发编程这么难我们为什么还要编写并发程序啊?
有时候我们在学并发编程的时候,有没有一种感觉叫身体掏空,有没有感觉叫我太难了
[图片上传失败...(image-8143c2-1605781546796)]
那有没有种感觉叫一眼就认准你了,虽然并发编程很难,但是线程是 Java 语言不可或缺的重要功能,它可以使复杂的异步代码变得简单从而极大的简化复杂的系统开发,另外用简单的方式使用线程方便发挥多处理器的强大计算能力。
并发发展背景
在早期的计算机中不包含操作系统,它们都是从头到尾只执行一个程序,并且程序能访问所有的计算机的资源。在裸机的情况下,不仅很难编写和运行,而且每次只能运行一次程序,对于计算机来说是一种浪费。
操作系统的出现使得计算机每次能执行多个程序,并且不同程序都在独立的进程中运行,操作系统为各个独立执行的进程分配各种资源,包括内存,文件句柄以及安全证书,如果需要,会在不同的进程中通过一些粗粒度的通信机制来交换数据,包括:套接字,信号处理,共享内存,信号量以及文件等。
为什么要在计算机中加入操作系统来实现多个程序的同步执行?
主要是因为下面几种原因:
资源利用率
在某些情况下,程序必须等待某个外部操作执行完
公平性
不同的用户和程序对于计算机的资源有着同样的使用权。
便利性
在计算机多个任务时,编写多个程序,每个程序执行多个任务并在必要时相互通信
促使进程和线程的出现因素有:资源利用,公平性,以及便利性
线程允许在同一个进程中存在多个程序控制流,线程会共享进程范围内的资源,例如:内存句柄和文件句柄。
线程的优势
线程使用得当,可以有效的降低程序的开发和维护成本,另外也可以提高性能,线程能够将大部分的异步工作流转换为串行工作流,还可以降低代码的复杂度
安全性问题
线程安全性可能是很复杂的,在没有充足同步的情况下,多个线程中操作顺序是不可预测的,甚至会产生奇怪的结果。UnsafeSequence 这个类将产生一个正整数值序列,该序列的每一个值都是唯一的
package com.yang.bthread;
import net.jcip.annotations.NotThreadSafe;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@NotThreadSafe
public class UnsafeSeuence {
private int value;
//返回唯一的值
public int getValue() {
return value++;
}
}
UnsafeSeuence 问题在于,如果执行时不对,那么两个线程调用就会出现相同的值
[图片上传失败...(image-90969e-1605781546796)]
上面是线程之间的交替执行的情况,执行从左到右的顺序递增,每一行表示一个线程的动作,这些交替执行会出现的情况
@NotThreadSafe 这个注解表示类和类成员的并发属性。
@ThreadSafe 这个注解可以大胆的在并发环境下使用此注解
在多线程环境下,getvalue 是否返回的是唯一值,要取决于运行时对线程中操作交替方式,因为多个线程要共享相同的内存地址空间,并且并发运行,因此它们可能会访问或者修改正在使用的变量。
那怎么解决程序的交替问题呢?
可以@ThreadSafe 用注解
package com.yang.bthread;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.NotThreadSafe;
import net.jcip.annotations.ThreadSafe;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ThreadSafe
public class UnsafeSeuence {
@GuardedBy("this") private int value;
//返回唯一的值
public synchronized int getValue() {
return value++;
}
}
如果没有同步,那么无论是编译器,硬件,还是运行都可以随意安排操作的时间和顺序。
活跃问题
活跃问题是指当某个操作无法继续执行下去,就会发生活跃问题。活跃问题的形式之一就是无限循环
性能问题
性能问题包含多方面,例如:服务时间过长,响应不灵敏,吞吐率过低,资源消耗过高,可伸缩性较低
网友评论