Java 并发编程之对象的共享(二)
2014-08-20 15:41
232 查看
线程封闭
一般在单线程内访问数据就不需要同步,这种技术叫做线程封闭,在Swing中大量使用了线程封闭技术,Swing的可视人化组件和数据模型对象都不是线程安全的,Swing通过将它们封闭到Swing的事件分发线程中来实现线程安全性。线程封闭的另一个常见应用是JDBC的Connection对象,JDBC规范并不要求Connection对象必须是线程安全的。应用程序服务器连接池是线程安全的,连接池通常会由多个线程同时访问,因此非线程安全的连接池是毫无意义的。
一个安全的线程池通常要实现下列接口
package mysql; import java.sql.*; import java.sql.ResultSet; public interface Pool { public boolean start(String dbname,String user,String psw); //启动数据库连接池服务 //以下start函数将允许用户设置最低空闲连接数,最高空闲连接数,最大连接数 public boolean start(int lows,int maxs,int maxc,String dbname,String user,String psw); public Connection getConnection(); //得到连接器 public boolean freeConnection(Connection con);//将连接返回到连接池中 public boolean close(); //清除连接池,并且关闭它(使之变得不可用) }
Ad-hoc线程封闭
这个是指,维护线程封闭性的职责完全由程序实现来承担,Ad-hoc线程封闭是非常脆弱的。因为没有语言特性可以将对象封闭到目标线程上,事实上对线程封闭对象的引用通常保存在公有变量 中。栈封闭
栈封闭是线程封闭的一种特例。在栈封闭中只能通过局部变量才能访问对象。public int loadTheArk(Collection<Animal> candidates) { SortedSet<Animal> animals; int numpairs = 0; Animal cnadidate = nul; animals = new TreeSet<Animal>(new GenderComparator()); animals.addAll = (candidates); for (Animal a : animals) { if (candidates == null || !candidates.isPotentalMate(a)) { cnadidate = a; } else { ark.load(new AnimalPair(candidates, a)); ++numpairs; candidates = null; } } return numpairs; }例如上面程序的Numpairs对象。无论如何都不会破坏栈封闭性。由于任何方法 都 无法 获得对基本类型的引用。同时只有一个引用指向集体animals,这个引用被封闭在局部变量中,因为也被封闭在执行线程中。
ThreadLocal类
维持线程封闭性的一种更规范的方法是使用ThreadLocal。这个类能使线程中的某个值与保存值 的对象关联起来。它提花了get与set等 访问接口或方法,这个方法为每个使用该 变量的纯种都 存有一个独立 的副本,因此get总是返回由当前执行线程在调用set时设置 的最新值。public static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { public Connection initialValue() { return DriverManager.getConnection(url); } }; public static Connection getConnection() { return connectionHolder.get(); }
这个ThreadLocal相当于 一个单线程池。当某个频繁执行的操作需要一个临时对象 ,例如 一个缓冲 区,而同时又希望避免在每次执行时都重新分配该临时对象,就可以使用这项技术 。
它会降低可重用性,也会在类之间引入隐含的耦合性,所以在使用格外小心 。
为此还做了一个小实验证明其线程安全性。
public class unsafe { public static ThreadLocal<Integer> connectionHolder = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { // TODO Auto-generated method stub int a = 1; return a; } }; public static void main(String[] Args) { new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub connectionHolder.set(2); } }).start(); System.out.println(connectionHolder.get()); connectionHolder.set(2); System.out.println(connectionHolder.get()); } }输出结果 :
1
2
证明只可以在主线程中对其进行修改。
不变性
不可变的对象一定是线程安全的。但是不可变不等于将所有的域都声明为final类型,即使这么做了那么这个对象仍然是可变的,因为在final类型的域中可以保存对可变对象的引用 。举个栗子
import java.util.ArrayList; public class unsafe { private final static java.util.List<Integer> unsafevalue = new ArrayList<Integer>(); public static void main(String[] agrs) { unsafevalue.add(2); System.out.println(unsafevalue.get(0)); } }如果这上面个类有个get方法可以得到unsafevalue,那么仍然可以对final声明的域进行修改。
当满足三个条件时,对象才是不可变的。上面final的声明只是条件之一
对象创建以后其状态不能被修改
对象所有域都是Final类型
对象 是正确创建的(没有this引用逸出)
再举个栗子
import java.util.ArrayList; public final class unsafe { private final static java.util.List<Integer> unsafevalue = new ArrayList<Integer>(); unsafe() { unsafevalue.add(2); unsafevalue.add(3); unsafevalue.add(4); } public boolean isExist(int t) { if (unsafevalue.contains(t)) { return true; } return false; } }
一个好的编程习惯:
除非需要更高的可见性,否则都声明为私有域,除非需要变化,否则都声明为final类型。
安全发布的常用模式
在静态初始化函数中初始化一个对象引用
将对象的引用保存到volatile类型的域或者 AtomicReferance对象 中
将对象的引用保存到某个正确 的构造对象中Final类型域中
将对象 的引用保存到一个由锁保护的域中
java的线程安全库中提供了一下安全发布保证
通过将一个键或者值放入 Hashtable,synchronizedMap或者ConcurrentMap中,可以安全的将它发发布给任何从这个引起窗口中访问它的线程
通过将某个元素放入Vector,CopyOnWriteArrayList,CopyOnWriteArraySet.synchronizedList或synchronizedSet中,可以将元素安全的发布
通过 将某个元素放在BLockingQueue或者ConcurrentLinkedQueue中。可以将元素安全的发布
通常要发布一个静态构造的对象 ,最简单和最安全的方式就是使用静态的初始化容器
静态初始化器由JVM在类的初始化阶段执行,由于在jvm内部存在着同步机制,因为通过 这种方式初始化的任何对象 都可以安全的发布。换句话说,就是声明为静态类型的具有最高优先级。
参考资料《java 并发编程实战》
相关文章推荐
- 【Java并发编程实践】线程安全性、对象的共享和对象的组合
- Java 并发编程之对象的共享
- Java并发编程学习——《Java Concurrency in Practice》学习笔记 3.对象的共享
- 【Java并发编程一】线程安全和共享对象
- java 并发编程实战 之 对象的共享
- [Java 并发] Java并发编程实践 思维导图 - 第三章 对象的共享
- java并发编程 第三节 对象的共享
- java 并发编程---安全共享对象策略
- Java并发编程之线程安全性和对象的的共享
- Java多线程编程(六)-并发编程原理(Java存储模型和共享对象)
- Java并发编程实践-第三章-对象的共享
- java并发编程实战-对象的共享
- [Java并发编程实战] 对象的共享
- Java并发编程学习——对象的共享
- 并发编程初探-对象的共享
- Java多线程编程核心技术---对象及变量的并发访问(二)
- 并发编程实战--对象的共享
- JAVA并发编程学习笔记------对象的可见性及发布逸出
- java并发编程 之 并发集合对象
- Java多线程编程核心技术---对象及变量的并发访问(一)