当前课程知识点:JAVA程序设计进阶 >  第三章 线程(下) >  3.1 线程安全与线程兼容与对立 >  Video

返回《JAVA程序设计进阶》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《JAVA程序设计进阶》慕课在线视频列表

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

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所放弃的

也就是说不推荐

大家调用这些方法

那这一节的内容

我们就介绍到这里

JAVA程序设计进阶课程列表:

第一章 线程(上)

-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

第六章 Java虚拟机

-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

第七章 深入集合Collection

-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

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。