当前课程知识点:JAVA程序设计进阶 > 第三章 线程(下) > 3.1 线程安全与线程兼容与对立 > Video
这一节我们将介绍
线程安全的概念
以及线程兼容与对立的概念
什么是线程安全
当多个线程访问同一个对象时
如果不用考虑这些线程
在运行时环境下的
调度和交替执行
也不需要进行额外的同步
或者在调用方
进行任何其他的协调操作
调用这个对象的行为
都可以获得正确的结果
那么这个对象就是线程安全的
那实现java的线程安全
有多种方式
包括不可变的这些对象
包括绝对线程安全
相对线程安全
以及线程的兼容和对立
那不可变指的是什么呢
我们的线程
在进行数据访问的时候
如果它访问的这些数据或者类
是一个不可变更的这个类
或者对象
那这个本身就是属于线程安全的
那这些不可变的对象
它首先可以通过final来修饰
比如说我们定义一个常量
public final a等于100
那如果多个线程访问的
是这么一个常量的话
那本身这个程序就是线程安全的
那也有可能我们访问的是
java.lang.String这个类
那以前我们学过之中也知道
String字符串这个类
它其实是一个常量类
那不可变的这个方式还可以
包括是枚举类型
比如说我们在程序当中
定义了一个枚举的数据对象
public enum Color
那这个本身是个枚举类型的话
它也是一个不可变的一个对象
那基于它来去做到
线程的访问的话
就可以实现线程安全
那其他不可变的这些对象
还包括java.lang.Number
这个类的子类
比如long 或者Double
甚至是BigInteger
或者BigDecimal
这些属于数字类型的
高精度实现的类
都属于不可变的对象
什么是绝对线程安全
那在前面几页PPT中
我们已经介绍了
满足Brian Goetz
在《Java Concurrency
In Practice》
这本书中定义的线程
就称作为绝对线程安全
那在我们Java的API当中
有好些类它也自己标注
称之为线程安全的
比如说Java.util.Vector包
当中的相量类Vector
但是这些类都不能算作是
绝对线程安全
在某些情况下也会出错
那如果我们想达到
绝对线程安全的目的的话
我们还要在外部
加以一些同步的控制
相对线程安全
什么是相对线程安全
那通常意义上的线程安全
需要保证这个对象单独操作
是线程安全的
调用的时候不需要做
额外的保障措施
但是对一些特定顺序的连续调用
就有可能导致它产生错误
这个时候就需要在调用时
使用同步手段
保证调用的正确性
那下面我们会看到一个例子
就有关于这个Vector
这个类的一个例子
我们这个例子主要是为了
向大家展示一下
我们一些java API中类
它在碰到这个线程操作的时候
有可能产生线程出错的这个情况
我们来看一下这个类的代码
import java.util.star
我们看一下这个类名
pubic class VectorSafe
这是有关线程安全的
它的一个成员变量
private static Vector
=new Vector
那这个时候
我们定义一个Vector对象
那它的类型是一个Vector
就是相量这个类型
那在这个相量当中
每个元素都是整型
我们接下来看一下我们的主方法
public static void main
String args
那在主方法里面
首先是一个无限循环
while true
紧接着有一个小循环
for int等于0
i小于10 i加加
然后这时候vector.add i
那我们通过这个小循环
我们这个线程 相量添加元素
总共添加了10个元素
再往下的代码是
Thread remove Thread
=new Thread new Runnable
这个代码的话是有点意思
实际上它的目的
是想定义一个线程
那定义这个线程的时候
它在实例化的时候
它是实例化一个匿名类
它是通过new Runnable这个接口
那底下具体这个匿名类的话
做了哪些事呢
主要看这个run方法
public void run里面
我们做了一个循环
for int i=0 i vector size
然后再i加加
然后这个循环过程当中
我们要对这个相量
进行删除操作
vector remove i
那就把它的元素
就这个相量中的元素要删除掉
好 刚才那个线程的话
就是不停的从相量中删除元素
那我们再看一下
我们第二个线程
Thread printThread
等于new Thread
new Runnable
那它也是采用匿名类的方式
来去定义我们这个线程
那这个线程的话
它的主要的内容
就看我们的run方法
public void run
for int i等于0
i小于vector.size i加加
我们循环便利我们整个相量
紧接着System.out.println
vector.get i
依次读取相量当中的每个元素
并把它打印出来
那这个printThread
这个线程也定义完毕
那我们接着往下看
removeThread start
就是删除相量元素的
那个线程启动
printThread.start
打印相量元素的线程也启动
然后while Thread
active Count大于20
那这句代码主要作为
就是要控制我们这个程序
在运行过程当中
所产生的线程的数量
总数不超过20个
那这样一个程序运行起来
会是什么样一个情况呢
那大家如果有机会的话
回到自己的家里
或者这实验室里边
可以把这个代码
在你的电脑上进行运行
但是运行过程当中
它不经常出错
但是偶尔也会出错
那出现了什么样的错误呢
出现了数组下标越界的错误
那这个产生错误的原因是什么
那最重要的原因就是
我们刚才有两个线程
一个叫这个Thread remove
另外一个线程
叫Thread print
这两个线程
都在同时访问一个数据
就是我们的相量vector
那其中一个线程的操作就是
删除我们相量中的元素
另外一个线程的操作
就是读取我们相量中的元素
大家看到这其实这两个操作
是有点互逆的 互斥的
那在这个读写相量的过程当中
就有可能产生错误
那从我们发现了
这个运行的结果当中
也发现了这一点
那我们怎么去改进这个程序呢
用什么办法
其实这个办法
在我们前两节的这个
前两章介绍线程的内容当中
已经提到了
我们看这个PPT
首先我们对我们的
remove Thread这个线程
做一个改进
那改进的地方的话
我已经给大家标出来了
就是我们这个红色字体
synchronized这个部分
实际上就是我们给我们的相量
加上了同步机制
大家可以看到我们代码中
synchronized后面
跟着vector这个相量对象
那后面就是它的这个循环
那从这个代码大家可以看出
就是我们对remove Thread
它的这么一个改造
就是要求在这个
remove Thread线程当中
在它反问相量
这个数据对象的时候加上同步
不允许其它线程
同时还访问这个相量
这样的话就能保证
我们这个相量的数据的安全性
那同样的道理
我们也需要去改进一下
我们的print Thread这个线程
那改进的办法也是同样的道理
是把run方法当中
我们对于vector这么一个对象
我们加上了synchranized
就是加上了同步机制
然后再对它进行这个访问
那就是访问的时候
就是做一个循环
然后把它的相量当中的
每个元素给取出来
所以我们通过这个synchranized
加上同步机制以后
可以有效的去改善
我们这些线程的安全性
那下面我们介绍一下另外的概念
叫做线程兼容和线程对立
什么叫线程兼容
也就是说我们这个
在程序运行过程当中
我们的线程所要访问的对象
它本身并不提供
线程安全的这个机制
但是我们可以通过
在调用或者访问这些对象的时候
采用同步手段来保证这些对象
在并发环境当中
可以安全的被访问
这种就称之为线程兼容
那与之相对的就是线程对立
也就是说我们在访问
这些对象的时候
我的线程无论在调用端
是否采取了同步措施
都无法在多线程的环境中
保证这个并发使用的安全性
那给大家举个例子
我们的线程类Thread类
过去曾经有个方法叫suspend
另外一个方法叫resume
那这两个方法的话
在JDK早期版本中是存在的
但是它的缺点就是
有可能导致死锁
所以后来JDK版本
已经声明放弃这两个方法
那如果大家下回再阅读
我们的java的JDK API的时候
你可以看到有些方法前面
标上了Deprecated
这样的这个字眼
那就表明说这样的方法
是被JDK所放弃的
也就是说不推荐
大家调用这些方法
那这一节的内容
我们就介绍到这里
-1.0 导学
--Video
-1.1 线程的基本概念
--Video
-1.1 线程的基本概念--作业
-1.2 通过Thread类创建线程
--Video
-1.2 通过Thread类创建线程--作业
-1.3 线程的休眠
--Video
-1.3 线程的休眠--作业
-1.4 Thread类详解
--Video
-1.5 通过Runnable接口创建线程
--Video
-1.5 通过Runnable接口创建线程--作业
-1.6 线程内部的数据共享
--Video
-2.0 导学
--Video
-2.1 线程同步的思路
--Video
-2.2 线程同步的实现方式—Synchronization
--Video
-2.3 线程的等待与唤醒
--Video
-2.4 后台进程
--Video
-2.5 线程的生命周期与死锁
--Video
-2.6 线程的调度
--Video
-3.0 导学
--Video
-3.1 线程安全与线程兼容与对立
--Video
-3.2 线程的安全实现-互斥同步
--Video
-3.3 线程的安全实现-非阻塞同步
--Video
-3.4 线程的安全实现-无同步方案
--Video
-3.5 锁优化
--Video
-4.0 导学
--Video
-4.1 URL对象
--Video
-4.2 URLConnection对象
--Video
-4.3 Get请求与Post请求
--Video
-4.4 Socket通信原理
--Video
-4.5 Socket通信实现
--Video
-5.0 导学
--Video
-5.1 Socket 多客户端通信实现
--Video
-5.2 数据报通信
--Video
-5.3 使用数据报进行广播通信
--Video
-5.4 网络聊天程序
--Video
-6.0 导学
--Video
-6.1 Java虚拟机概念
--Video
-6.2 Java虚拟机内存划分
--Video
-6.3 Java虚拟机类加载机制
--Video
-6.4 判断对象是否存活算法及对象引用
--Video
-6.5 分代垃圾回收
--Video
-6.6 典型的垃圾收集算法
--Video
-6.7典型的垃圾收集器
--Video
-7.0 导学
--Video
-7.1 集合框架与ArrayList
--Video
-7.2 LinkedList
--Video
-7.3 HashMap与HashTable
--Video
-7.4 TreeMap与LinkedHashMap
--Video
-7.5 HashSet
--Video
-8.0 导学
--Video
-8.1 Java反射机制
--Video
-8.2 Java静态代理
--Video
-8.3 Java动态代理
--Video
-8.4 Java 反射扩展-jvm加载类原理
--Video
-8.5 Java进阶课程总结
--Video