有条件线程安全.
事出于一次偶然的MS中,在问及hashmap和hashtable的时候很习惯的就说非线程安全和线程安全。却被告知有条件线程安全这一说法。
困惑之余查看了hashtable 和hashmap 的源码,
public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> 及
public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>,
Cloneable, Serializable
在Hashtable 中每一个方法都是synchronized同步的,也就是线程安全的。
查看资料发现,早有砖家提出了有条件线程安全这一概念。
并发专家Brian Goetz将Hashtable和Vector类描述为“有条件线程安全的”。一个类难道不是线程安全就是线程不安全的吗?不幸的是,线程安全并不是一个非真即假的命题。
一个类在可以被多个线程安全调用时就是线程安全的? 这可能是大部分人理解的线程安全。
砖家提出:
· ...可以从多个编程线程中调用,无需线程之间不必要的交互。· ...可以同时被多个线程调用,不需要调用一方有任何操作。
下面看看vector的一个例子
import java.util.List;
import java.util.Vector;
public class VectorTest {
List vector= new Vector();
public void init() {
for (int i=0; i<1000 ; i++) {
vector.add(i);
}
}
public void get(int i) {
vector.get(i);
}
public void remove(int i) {
vector.remove(i);
}
public void start() {
this.init();
new Thread(new ListOpt(vector)).start();
for (int i=0; i<100 ; i++) {
new Thread(new ListOpt1(vector)).start();
}
}
public static void main(String[] args) {
VectorTest test = new VectorTest();
test.start();
}
class ListOpt implements Runnable {
private List list;
public ListOpt(List list ) {
this.list = list;
}
public void run() {
try {
for (int i=0 ;i<1000; i++) {
int listsize= list.size();
System.out.println(list.get(listsize-1));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ListOpt1 implements Runnable {
private List list;
public ListOpt1(List list ) {
this.list = list;
}
public void run() {
try {
list.remove(list.size()-1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果大家也可以预料的到的
顺利执行完成
或
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: ***
at java.util.Vector.get(Unknown Source)
at VectorTest$ListOpt.run(VectorTest.java:44)
at java.lang.Thread.run(Unknown Source)
可能有人这时候就要说,run 方法中的Vector每一个方法都是同步的,这不能作为线程不安全的依据
问题代码在于:
int listsize= list.size();
System.out.println(list.get(listsize-1));
这一问题是由get()的前置条件是以size()的结果来定义的这一事实所带来的。只要看到这种必须使用一种方法的结果作为另一种讲法的输入条件的样式,它就是一个状态依赖,就必须保证至少在调用这两种方法期间元素的状态没有改变。一般来说,做到这一点的唯一方法在调用第一个方法之前是独占性地锁定对象,一直到调用了后一种方法以后。在上面的迭代Vector元素的例子中,需要在迭代过程中同步Vector对象。
再回过头来看看
线程安全性 类要成为线程安全的,首先必须在单线程环境中有正确的行为。如果一个类实现正确(这是说它符合规格说明的另一种方式),那么没有一种对这个类的对象的操作序列(读或者写公共字段以及调用公共方法)可以让对象处于无效状态,观察到对象处于无效状态、或者违反类的任何不可变量、前置条件或者后置条件的情况。 此外,一个类要成为线程安全的,在被多个线程访问时,不管运行时环境执行这些线程有什么样的时序安排或者交错,它必须仍然有如上所述的正确行为,并且在调用的代码中没有任何额外的同步。其效果就是,在所有线程看来,对于线程安全对象的操作是以固定的、全局一致的顺序发生的。 正确性与线程安全性之间的关系非常类似于在描述 ACID(原子性、一致性、独立性和持久性)事务时使用的一致性与独立性之间的关系:从特定线程的角度看,由不同线程所执行的对象操作是先后(虽然顺序不定)而不是并行执行的。
上面例子中的方法之间的状态依赖关系似乎破坏了整个类的一致性和独立性。
不可变 不可变的对象一定是线程安全的,并且永远也不需要额外的同步。因为一个不可变的对象只要构建正确,其外部可见状态永远也不会改变,永远也不会看到它处于不一致的状态。Java 类库中大多数基本数值类如 Integer 、 String 和 BigInteger 都是不可变的。
线程安全 由类的规格说明所规定的约束在对象被多个线程访问时仍然有效,不管运行时环境如何排列,线程都不需要任何额外的同步。这种线程安全性保证是很严格的 -- 许多类,如 Hashtable 或者 Vector 都不能满足这种严格的定义。
所以。。。
分享到:
相关推荐
JAVA中如何实现多线程(重点!!) 168 通过继承Thread类实现多线程 168 通过Runnable接口实现多线程 169 线程状态和sleep/yield/join/stop/destroy方法 170 新生状态 170 就绪状态 170 运行状态 170 死亡状态 170 ...
二级java 公共基础知识部分30分 专业语言部分 70分 Java语言程序设计 基本要求: 1. 掌握Java语言的特点,实现机制和体系结构。 2. 掌握Java语言中面向对象的特性。 3. 掌握Java语言提供的数据类型和结构。 4. 掌握...
java.util.concurrent.atomic 类的小工具包,支持在单个变量上解除锁的线程安全编程。 java.util.concurrent.locks 为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器。 java.util.jar 提供读写 ...
java为数据结构中的映射定义一个接口java.util.Map,有四个实现类HashMap Hashtable LinkedHashMap TreeMap用法和区别;对Map排序; 5字符串 使用String;判断一个字符串是否是合法的java标识符;使用StringBuffer;...
Java基础 6 1. 面向对象的特征有哪些方面 6 2. String是最基本的数据类型吗? 7 3. int 和 Integer 有什么区别 7 4. String 和StringBuffer的区别 7 5. 运行时异常与一般异常有何异同? 7 6. 说出ArrayList,Vector, ...
org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。 org.omg.CORBA 提供 OMG CORBA API ...
一、Java基础知识 1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,如:输入abc,输出cba 写一个方法,实现字符串的替换,如:输入...
org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。 org.omg.CORBA 提供 OMG CORBA API ...
由于比较大分为两个部分,这是第一...org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。 ...
46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
学生提问:为什么有栈内存和堆内存之分? 93 4.6.2 基本类型数组的初始化 95 4.6.3 引用类型数组的初始化 96 4.6.4 没有多维数组 99 学生提问:我是否可以让图4.13中灰色覆盖的数组元素再次指向另一个数组?这样...
引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...
引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...
第5-20章深入描述了java技术的内部细节,包括垃圾收集、java安全模型、java的连接模型和动态扩展机制、class文件、运算及流程控制等等,其中等6章和附录a-c完全可以作为class文件和指令含集的参考手册。本书还附带...
由于文件比较大 分为两个部分,这是...org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。...
11、解释Java中的基本语法,包括变量、数据类型、控制结构等。 12、解释Java中的数组是什么,以及如何使用数组? 13、解释Java中的字符串是什么,以及如何使用字符串? 14、解释Java中的条件语句和循环语句是什么,...
27、Java中有多少种数据结构,分别是什么? 76 28、Arraylist 和Linkedlist 的区别 76 29、List遍历方式有多少种 76 30、Map怎么遍历 76 31、怎么获取Map所有的key,所有的value 77 32、获取Class的实例有几种方式 ...
第2周介绍Java类库,包括向量、堆栈、映射、散列表和位组等数据结构,以及Swing组件、布局管理器和Java Web Start等;第3周介绍高级主题,包括输入和输出、对象序列化、通过Internet进行通信、使用数据库、XML、Web...