并发编程2 对象共享

1,当中主要是多线程共享数据情境下的基本概念介绍
Java面向对象编程更多的是对共享对象的访问

一:对象的发布与逸出

发布:
使对象在当前使用域之外的地方可以使用该对象,可以将对象的引用保存到其他代码可以访问的地方(例如非私有变量/静态变量),使用非私有方法返回对象的引用–提供了一个可以访问对象的方法/修改对象可变状态的方法。

1-1
//例如
public class Test{
     public Object obj;
	public Object getObj(){
		return new Test();
	}
	public void setObj(){
		obj = new Test();
	}
}

有时候我们不需要将对象发布出去,有时候我们又需要将对象发布,此时就需要一定的同步处理
逸出:
当对象不需要溢出,但是却发布时就叫做:逸出
常见的逸出:this 逸出

1-2
//1. 不安全的构造函数this 逸出

//2. 内部类,隐式this 逸出
public class Outer {
	private int id;
	public class Inter{
		public  void get(){ //在这个类中传递了外部类的this 对象,可以修改外部类的状态
			return id;
		}
	}
}

当发布一个对象时,这个对象的所有非私有引用的多有对象都会被发布,当将一个对象传递给某个pubic 方法时,就相当于这个对象被发布,


二:封闭性

当访问可共享的可变数据时,通常需要同步。一种避免使用同步的方法就是不共享数据,仅仅单线程内访问数据。

线程封闭

常见的例子:JDBC 中的Connection对象,JDBC并不要求Connection时线程安全的,线程直接从连接池中获取一个connection 实例,使用完之后再将对象返回给连接池,在连接没有返回时,连接池不会给其他线程分配该连接对象,,这样就将Connection隐式的封装在了线程中,Java中支持线程封闭的机制:局部变量,ThreadLocal 类
栈封闭:
只能通过局部变量来访问对象,方法执行完成,出栈之后栈中的局部变量都会被回收。

1-3
public void test(){
	//栈封闭,要保证栈中的对象不会逸出就行
	Animal animal = new Animal();
}

ThreadLocal 类:
这是一个Java本身自带的类,这个类能使线程中的某个值和需要保存的值联系起来(值保存在线程中),每个线程操作自己的副本数据,相当于给当前线程创建的局部变量(栈封闭的局部变量是方法中的),线程结束相关数据就会被回收
Thread Local 一般用来防止单实例(一个类只有一个实例)变量的访问,例如:
JDBC中为了在调用每个方法时都要传递connection 对象,所以将connection 对象保存在线程中

1-4
public class TestDaoNew{
	private static ThreadLocal<COnnection> connThread = new ThreadLocal<Connection>();
	//将连接保存在线程中
	public static Connection getConnection(){
		if(connThread.getConnection()==null){
			Connection conn = new Connection(...);
			connThread.set(conn);
		}
	}
	//释放连接资源
	public void cleanConnection(){
		getConnection().clean(); //直接返回线程中保存的连接
	}	
}

数据库操作中的事务的上下文也可以保存在线程中。
ThreadLocal 可以看作一个<Thread , E> 的结构,保存当前线程和对象。


三:不变性

数据是共享的但是数据无法被修改/它的状态只能由自己的构造函数决定,这也是线程安全的(不变对象一定是线程安全的)
不变对象的特点:

  1. 安全的构造,在构造的过程中不会出现逸出
  2. 所有的域都使用final 修饰

注意:不可变的对象和不可变的对象引用是有区别的

虽然不变性不存在修改出现的不安全,但是依然存在可见性问题,对象构造完成后其他的线程也可能无法看见对象的状态,所以还是需要Volatile 的修饰

public class Cache{
	private final int a;
	private final int b;
	public Cache(int x,int y){
		a = x;
		b = y;
	}
}

private volatile Cache cache = new Cache(0,0);

四:对象的安全发布

首先确保不是逸出
不安全发布的例子:

1-5
public Holder holder;

public void initialize(){
	holder = new Holder(...);
}

为什么说这个holder 对象的发布是不安全的,首先他没有逸出。但是在多线程的情况下,存在可见性的问题,其他线程看见的Holder 的对象的状态是不定的,所以这样不正确的发布可能导致其他线程看见尚未成功创建的对象

所以在对象的发布中/构造中。要保证对象的安全发布

  1. 在类的静态初始化函数中发布该对象

  2. 将对象的引用保存到Volatile 修饰的域中

    1-6
    public volatile Holder holder;
    
    public void initialize(){
    	holder = new Holder(...);
    }
    //这样的发布就是正确的
    
  3. 这个对象为不可变对象,那么就算是1-5 的构造过程,发布也是安全的,这是因为JVM对不可变对象的特殊处理,保证了构造的安全

  4. 将对象的引用保存在一个由锁保护的域中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值