Java并发编程实战3章
添加时间:2013-6-17 点击量:
1.同步包含两方面:原子性和可见性。
2.可见性:因为在多线程法度中,若是没有采取正确的同步,有些线程就会获得失效数据。
- Java内存模型请求,变量的读取操纵和写入操纵都必须是原子操纵,但对于非volatile类型的long和double变量,JVM容许将64位的读操纵或写操纵分化为两个32位的操纵。当读取一个非volatile类型的long变量时,若是对该变量的读操纵和写操纵在不合的线程中履行,那么很可能会读取到某个值的高32位和另一个值的低32位。即使不推敲失效数据题目,在多线程法度中应用共享且可变的long和double等类型的变量也是不安然的,除非用关键字volatile来声明它们,或者用锁保护起来。
- 加锁的含义不仅仅局限于互斥行动,还包含内存可见性。为了确保所有线程都能看到共享变量的新值,所有履行读操纵或者写操纵的线程都必须在同一个锁上同步。
- 下面的代码是书中例子,若是多线程接见这个类,就存在可见性题目,然则如何测试获得比如输出为0的成果或者法度无法终止?求赐教!
public class NoVisibility {
private static boolean ready = false;
private static int number = 0;
public static class ReaderThread extends Thread {
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println(number); //如何测试输出0呢?
}
}
/
@param args
/
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
3.volatile变量:用来确保将变量的更新操纵通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都邑重视到这个变量是共享的,是以不会将该变量上的操纵与其他内存操纵一路重排序。volatile变量不会被缓存在存放器或者对其他处理惩罚器不成见的处所,是以在读取volatile类型的变量时总会返回新写入的值。
- 加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
- 当且仅当满足以下所有前提时,才应当应用volatile变量:
- 对变量的写入操纵不依附变量的当前值,或者你能确保只有单个线程更新变量的值。
- 该变量不会与其他状况变量一路纳入不变性前提中。
- 在接见变量时不须要加锁。
4.线程封闭:当接见共享的可变数据,凡是须要应用同步。一种避免应用同步的体式格式就是不共享数据。若是仅在单线程内接见数据,就不须要同步。这种技巧被称为线程封闭
三种体式格式实现:
- Ad-hoc线程封闭
- 栈封闭
- ThreadLocal类
5.不变性:不成变对象必然是线程安然的。
当满足一下前提时,对象才是不成变的:
- 对象创建今后其状况就不克不及批改。
- 对象的所有域都是final类型。
- 对象是正确创建的(在对象的创建时代,this引用没有逸出)。
6. 下面这个Holder类是“未被正确公布”,它存在两个题目,起首,除了公布对象的线程外,其他线程可以看到的Holder域是一个失效值,是以将看到一个空引用或者之前的旧值,然而,更糟糕的景象是,线程看到Holder引用的值是新的,但Holder状况的值倒是失效的。景象变得加倍不成猜测的是,某个线程在第一次读取域时获得失效值,而再次读取这个域时会获得一个更新值,这也是assertSainty抛出AssertionError的原因。我想知道如何测试,能抛出AssertionError异常来。
public class Holder {
private int n;
public Holder(int n) throws InterruptedException {
this.n = n;
}
public void assertSanity() {
if (n != n) {
throw new AssertionError(This statement is false); //如何测试抛出该异常?
}
}
}
我所有的自负皆来自我的自卑,所有的英雄气概都来自于我的软弱。嘴里振振有词是因为心里满是怀疑,深情是因为痛恨自己无情。这世界没有一件事情是虚空而生的,站在光里,背后就会有阴影,这深夜里一片寂静,是因为你还没有听见声音。—— 马良《坦白书》
1.同步包含两方面:原子性和可见性。
2.可见性:因为在多线程法度中,若是没有采取正确的同步,有些线程就会获得失效数据。
- Java内存模型请求,变量的读取操纵和写入操纵都必须是原子操纵,但对于非volatile类型的long和double变量,JVM容许将64位的读操纵或写操纵分化为两个32位的操纵。当读取一个非volatile类型的long变量时,若是对该变量的读操纵和写操纵在不合的线程中履行,那么很可能会读取到某个值的高32位和另一个值的低32位。即使不推敲失效数据题目,在多线程法度中应用共享且可变的long和double等类型的变量也是不安然的,除非用关键字volatile来声明它们,或者用锁保护起来。
- 加锁的含义不仅仅局限于互斥行动,还包含内存可见性。为了确保所有线程都能看到共享变量的新值,所有履行读操纵或者写操纵的线程都必须在同一个锁上同步。
- 下面的代码是书中例子,若是多线程接见这个类,就存在可见性题目,然则如何测试获得比如输出为0的成果或者法度无法终止?求赐教!
public class NoVisibility {
private static boolean ready = false;
private static int number = 0;
public static class ReaderThread extends Thread {
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println(number); //如何测试输出0呢?
}
}
/
@param args
/
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
3.volatile变量:用来确保将变量的更新操纵通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都邑重视到这个变量是共享的,是以不会将该变量上的操纵与其他内存操纵一路重排序。volatile变量不会被缓存在存放器或者对其他处理惩罚器不成见的处所,是以在读取volatile类型的变量时总会返回新写入的值。
- 加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
- 当且仅当满足以下所有前提时,才应当应用volatile变量:
- 对变量的写入操纵不依附变量的当前值,或者你能确保只有单个线程更新变量的值。
- 该变量不会与其他状况变量一路纳入不变性前提中。
- 在接见变量时不须要加锁。
4.线程封闭:当接见共享的可变数据,凡是须要应用同步。一种避免应用同步的体式格式就是不共享数据。若是仅在单线程内接见数据,就不须要同步。这种技巧被称为线程封闭
三种体式格式实现:
- Ad-hoc线程封闭
- 栈封闭
- ThreadLocal类
5.不变性:不成变对象必然是线程安然的。
当满足一下前提时,对象才是不成变的:
- 对象创建今后其状况就不克不及批改。
- 对象的所有域都是final类型。
- 对象是正确创建的(在对象的创建时代,this引用没有逸出)。
6. 下面这个Holder类是“未被正确公布”,它存在两个题目,起首,除了公布对象的线程外,其他线程可以看到的Holder域是一个失效值,是以将看到一个空引用或者之前的旧值,然而,更糟糕的景象是,线程看到Holder引用的值是新的,但Holder状况的值倒是失效的。景象变得加倍不成猜测的是,某个线程在第一次读取域时获得失效值,而再次读取这个域时会获得一个更新值,这也是assertSainty抛出AssertionError的原因。我想知道如何测试,能抛出AssertionError异常来。
public class Holder {
private int n;
public Holder(int n) throws InterruptedException {
this.n = n;
}
public void assertSanity() {
if (n != n) {
throw new AssertionError(This statement is false); //如何测试抛出该异常?
}
}
}
我所有的自负皆来自我的自卑,所有的英雄气概都来自于我的软弱。嘴里振振有词是因为心里满是怀疑,深情是因为痛恨自己无情。这世界没有一件事情是虚空而生的,站在光里,背后就会有阴影,这深夜里一片寂静,是因为你还没有听见声音。—— 马良《坦白书》