public class HibernateUtil { private static Log log = LogFactory.getLog(HibernateUtil.class); private static final SessionFactory sessionFactory; //定义SessionFactory static { try { // 通过默认配置文件hibernate.cfg.xml创建SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { log.error("初始化SessionFactory失败!", ex); throw new ExceptionInInitializerError(ex); } } //创建线程局部变量session,用来保存Hibernate的Session public static final ThreadLocal session = new ThreadLocal(); /** * 获取当前线程中的Session * @return Session * @throws HibernateException */ public static Session currentSession() throws HibernateException { Session s = (Session) session.get(); // 如果Session还没有打开,则新开一个Session if (s == null) { s = sessionFactory.openSession(); session.set(s); //将新开的Session保存到线程局部变量中 } return s; } public static void closeSession() throws HibernateException { //获取线程局部变量,并强制转换为Session类型 Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); } }在这个类中,由于没有重写ThreadLocal的initialValue()方法,则首次创建线程局部变量session其初始值为null,第一次调用currentSession()的时候,线程局部变量的get()方法也为null。因此,对session做了判断,如果为null,则新开一个Session,并保存到线程局部变量session中,这一步非常的关键,这也是“public static final ThreadLocal session = new ThreadLocal()”所创建对象session能强制转换为Hibernate Session对象的原因。
public class Student { private int age = 0; //年龄 public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }
import java.util.Random; public class ThreadLocalDemo implements Runnable { //创建线程局部变量studentLocal,在后面你会发现用来保存Student对象 private final static ThreadLocal studentLocal = new ThreadLocal(); public static void main(String[] agrs) { ThreadLocalDemo td = new ThreadLocalDemo(); Thread t1 = new Thread(td, "a"); Thread t2 = new Thread(td, "b"); t1.start(); t2.start(); } public void run() { accessStudent(); } /** * 示例业务方法,用来测试 */ public void accessStudent() { //获取当前线程的名字 String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName + " is running!"); //产生一个随机数并打印 Random random = new Random(); int age = random.nextInt(100); System.out.println("thread " + currentThreadName + " set age to:" + age); //获取一个Student对象,并将随机数年龄插入到对象属性中 Student student = getStudent(); student.setAge(age); System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge()); try { Thread.sleep(500); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge()); } protected Student getStudent() { //获取本地线程变量并强制转换为Student类型 Student student = (Student) studentLocal.get(); //线程首次执行此方法的时候,studentLocal.get()肯定为null if (student == null) { //创建一个Student对象,并保存到本地线程变量studentLocal中 student = new Student(); studentLocal.set(student); } return student; } }
可以看到a、b两个线程age在不同时刻打印的值是完全相同的。这个程序通过妙用ThreadLocal,既实现多线程并发,游兼顾数据的安全性。