并发:对象的共享和发布

本文参考《java并发编程实战》,java并发必读书籍

要编写正确的并发程序,关键问题在于:访问共享的可变状态需要正确的管理。

一、可见性(变量的更新操作通知到其他线程)

1.多个线程读写时对内存的可见问题。是因为java内存模型导致的。在之后的博文中会介绍内存模型

重排序是内存模型的一种表现

重排序:在没有同步的情况下,编译器、处理器以及运行时都可能对操作的执行顺序进行调整

 

2.所以共享必须  正确的同步

不同步会导致:产生失效数据

非原子的64操作就会得到失效值(备注:double/long, 在读写的时候会拆分成俩个32位的操作,俩个操作就有可能不同步,就会得到失效值)

 

3.加锁能保证可见性(不局限于互斥行为

上篇博文讲过内置锁就能保证线程之间数据共享

 

4.volatile关键字

稍弱的同步机制,比sychronized更轻量级的同步机制

编译器与运行时都会关注这个变量是共享的,所以不会重排序,valatile变量不会缓存在寄存器或者其他处理器不可见的地方

volatile通常用于某个操作完成、发生中断或者状态的标志

 

5.加锁与volatile

加锁:  确保可见性  又可确保原子性

volatile:确保可见性  但是不能确保原子性

 

二、发布与逸出

发布(Publish):使对象能够在当前作用域之外的代码中使用。

比如:a.对象的引用保存在其他类中可以访问的地方,b.某一个非私有的方法中返回该引用,c.引用传递到其他类的方法中

逸出(Escape):某个不应该发布的对象被发布了。

 

发布方式

1.共有静态变量发布:public static Set ss;//ss发布了

2.通过方法发布私有变量(逸出了,因为私有变量是私有了,不应该发布)

private String[] states = new String[] {"AA", "BB"};

public String[] getStates[] {

    return states;

}

 

3.内部类被发布(逸出了,内部类不应该发布)

 

4.最不容易发现的是this引用逸出。

不用在构造过程中使this引用逸出

一般使用工厂方法防止this指针逸出(可参考java并发实战)

 

三、线程封闭

含义:仅在单线程内访问数据

1.应用场景

Swing组件:封闭到Swing的事件分发线程中

JDBC(Java Database Connectivity)的Connection对象,一个连接对应一个线程

Spring事件机制

 

2.线程封闭的三种方式

方式一、Ad-hoc线程封闭

维护线程封闭的职责完全由程序来承担

方式二、栈封闭(也称为线程内部使用或者线程局部使用)

只能局部变量才能访问对象

同步变量也能使对象更容易封闭在线程中

方式三、ThreadLocal类(比较规范的方式,在框架中使用广泛)

ThreadLocal 提供get与set等接口为线程提供一份独立的副本,防止对可变的单实例变量或者全局变量进行共享

ThreadLocal<T> 等价于 Map<Thraad, T>,

举例

private static ThreadLocal<Connection> connectionHolder = 
    new ThreadLocal<Connection>() {
        public Connection initalValue() {
            return DriverManage.getConnection(DB_URL);
        }
    };

public static Connection getConnection() {
    return connectionHolder.get();
}

 

四、不变性

不可变对象一定是线程安全的

对象可变的条件:

1.对象创建以后其状态就不能修改

2.对象的所有域都是final类型

3.对象是正确创建的(在对象创建期间,this引用没有逸出)

编程习惯

所有域 尽量 private私有化

所有域 尽量 final

 

五、安全发布

任何线程都可以在不需要额外的同步的情况下安全地访问 不可变对象 , 即使在发布这些对象没有使用同步

 

对象的引用以及对象的状态安全发布模式方式

方式一:在静态初始化函数中初始化一个对象引用

方式二:将对象的引用保存到volatile类型的域或者AtomicReferance对象中

方式三:将对象的引用保存到某个正确构造对象的final类型域中

方式四:将对象的引用保存到一个由锁保护的域中

 

事实不可变对象:如果对象在发布后不会被修改,就是对象状态在发布后不会改变

在没有额外的同步的情况下,任何线程都可以安全发布的

 

可变对象:对象在构造后可以修改,只能确保“发布当时”状态的可见性

 

对象发布总结:

不可变对象可以通过任意机制发布

事实不可变对象:必须通过安全方式发布

可变对象:必须通过安全方式发布,并且必须是县残缺的或者由某个锁保护起来

 

并发程序中使用和共享对象时的策略:

线程封闭:只能由一个线程拥有,对象封闭在该线程中,只能在该线程修改

只读共享:任何线程都不能修改。共享只读对象包括不可变对象和事实不可变对象

线程安全共享:内部实现同步,通过对象的公有接口来进行访问而不需要进一步同步。

保护对象:只能通过持有特定的锁来访问。

保护对象包括封装在其他线程安全对象中的对象,以及已发布的并且由某个特定锁保护的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值