欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

共享对象

程序员文章站 2022-07-05 12:54:58
...

共享对象

可见性

确保跨线程写入的内存可见性,必须使用同步机制。
案例:

public class NoVisibliity{
    private static boolean ready;
    private static int number;

    private static class ReaderThread extends Thread{
        public void run(){
            while(!ready){
                Thread.yield();
                System.out.println(number);
            }
        }
        public static void main(String[] args){
            new ReaderThread().start();
            number=42;
            ready=true;
        }
    }
}

主程序运行可能会出现0的情况,程序运行存在“重排序”的问题。

过期数据

导致意外的异常、脏数据、错误的计算和无限的循环。

非原子性的64位操作

double long数值变量最好声明为volatile类型或用锁保护起来,JVM将64位读写划分为两个32位操作,就有可能出现问题。

锁和可见性

  • 内置锁保证了可见性。
  • 读取和写入线程必须使用公共的锁进行同步。

Volatile变量

  • 一种同步的弱形式
  • 相比于synchronized而言,是轻量级的同步机制。
  • 写入volatitle变量就类似于退出同步块,读取就是进入同步块。
  • 加锁可以保证原子性和可见性,volatitle只能保证可见性。
  • 一般用在标识、中断、状态的标记
    案例:
volatitle boolean asleep;
...
    while(!asleep){
    ...
    //

    }
  • 使用条件:
    1、写入变量并不依赖变量的当前值。
    2、变量不需要与其他状态共同参与不变约束。
    3、访问变量时,没有其他原因需要加锁。

发布和逸出

1、发布

  • 方法持有一个对象的引用。
  • 发布的方法:将对象的引用存储到公共静态域中。
public static Set<Secret> knowSecrets;

public void initialize(){
    knowSecrets=new HashSet<Secret>();
}
  • 隐式允许this逸出
    内部类暴露
public class ThisEscape{
    public ThisEscape(EvenetSource source){
        new EventListener(){
        public void onEvent(Event e){
            doSomething(e);
    }
    }
}
}

2、逸出

  • 如果发布对象时,他还没有完成构造。

3、安全发布

  • 构造函数
  • 使用工厂方法防止this逸出
    如果想在构造函数中注册监听器或启动线程,可以使用一个私有构造函数和一个公共的工厂方法。
public class Listener{
    private final EvenetListener listener;

    private Listener(){
        listener=new EventListener(){
            public void onEvent(Event e){
            doSomething(e);
        }
    };
}
public static Listener newInstance(EvenetSource source){
    Listener safe=new Lisener();
    source.registerListener(safe):
    return safe;
}

线程封闭

  • 利用ThreadLocal实现