Java并发编程详解之 线程安全和对象共享 (四)

2014-11-24 10:41:04 · 作者: · 浏览: 1
thing(e);
}
};
}

public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}

public class SafeListener {
private final EventListener listener;

private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
};
}

public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
线程封闭
主要的线程封闭技术有:栈封闭和ThreadLocal类

栈封闭:把变量都声明为局部变量,并且不要使它们逸出

ThreadLocal类:这是维持线程封闭性更规范的一种方法,ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享。使用方法如下代码:

[java]
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionDispenser {
static String DB_URL = "jdbc:mysql://localhost/mydatabase";

private ThreadLocal connectionHolder
= new ThreadLocal() {
public Connection initialValue() {
try {
return DriverManager.getConnection(DB_URL);
} catch (SQLException e) {
throw new RuntimeException("Unable to acquire Connection, e");
}
};
};

public Connection getConnection() {
return connectionHolder.get();//当某个线程初次调用ThreadLocal.get方法时,就会调用initialValue来获取初始值。
}
}

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionDispenser {
static String DB_URL = "jdbc:mysql://localhost/mydatabase";

private ThreadLocal connectionHolder
= new ThreadLocal() {
public Connection initialValue() {
try {
return DriverManager.getConnection(DB_URL);
} catch (SQLException e) {
throw new RuntimeException("Unable to acquire Connection, e");
}
};
};

public Connection getConnection() {
return connectionHolder.get();//当某个线程初次调用ThreadLocal.get方法时,就会调用initialValue来获取初始值。
}
}

当某个频繁执行的操作需要一个临时对象,例如一个缓冲区,而同时又希望避免在每次执行时都重新分配该临时对象,就可以使用这项技术

开发人员经常滥用ThreadLocal,例如将所有全局变量都作为ThreadLocal对象,或者作为一种“隐藏”方法参数的手段。ThreadLocal变量类似于全局变量,它能降低代码的可重用性,并在类之间引入隐含的耦合性,因此在使用时要格外小心

不变性

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

当满足以下所有条件时,对象才是不可变的

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

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

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

一个编程过程中的良好习惯

正如“除非需要更高的可见性,否则应将所有的域都声明为私有域”是一个良好的编程习惯,“除非需要某个域是可变的,否则应将其声明为final域”也是一个良好的编程习惯

安全的发布
上面讨论的都是如何确保对象不被发布,现在开始讨论如何安全的发布

安全发布的常用模式:

要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式来安全地发布

(1)在静态初始化函数中初始化一个对象的引用

(2)将对象的引用保存到volatile类型的域或者AtomicReferance对象中

(3)将对象的引用保存到某个正确构造对象的final类型域中

(4)将对象的引用保存到一个由锁保护的域中(如将对象放入Vector或synchronizedList容器)