msql笔记七——ThreadLocal保证客户端同时拿到的是同一个连接,数据库多事务的处理
2016-08-12 01:41
525 查看
1、简介:JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。
2、jkd介绍:该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
3、个人理解:ThreadLocal相当于一个Map容器,里面的key是Thread,value是Object对象,对于每一个key都有对应的对象,而map维护的就是一个currenctThread对象(当前线程),可以在当前线程放入和设置Object对象,如果是在同一线程中,拿到的对象是同一个。下面我自己模拟了一个MyThreadLocal对象,其原理就是如此
THreadLocal使用代码:
详细使用,请参考mysql笔记8——MVC项目
2、jkd介绍:该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
3、个人理解:ThreadLocal相当于一个Map容器,里面的key是Thread,value是Object对象,对于每一个key都有对应的对象,而map维护的就是一个currenctThread对象(当前线程),可以在当前线程放入和设置Object对象,如果是在同一线程中,拿到的对象是同一个。下面我自己模拟了一个MyThreadLocal对象,其原理就是如此
package cn.hncu.threadLocalDemo; import java.util.HashMap; public class MyThreadLocal { private HashMap<Thread, Object> map=new HashMap<Thread, Object>();//实质上是一个map对象 public Object get(){ Thread nowThread=Thread.currentThread();//以当前线程作为key为准,若是相同的线程,值obj对象不变 Object obj =map.get(nowThread); return obj; } public void set(Object obj){ Thread nowThread=Thread.currentThread(); map.put(nowThread, obj);//吧当前线程的对象放入map中,下次拿到保证是同一个线程 } public void remove(){ Thread nowThread=Thread.currentThread(); map.remove(nowThread); } }
THreadLocal使用代码:
package cn.hncu.threadLocalDemo; import java.util.Random; import org.junit.Test; public class ThreadLocalDemo { static ThreadLocal<Object> tl=new ThreadLocal<Object>(); public static Object getvalue(){ Object obj1=tl.get(); if(obj1==null){ Random r=new Random(); obj1=r.nextInt(500); tl.set(obj1); } return obj1; } @Test public void test(){ Object obj1=getvalue(); Object obj2=getvalue(); System.out.println(obj1+" "+obj2); System.out.println(obj1==obj2); Object obj3=new A().aa(); System.out.println(obj2+" "+obj3); System.out.println(obj2==obj3);//true,相同线程 System.out.println("____________"); final Object obj4=new B().bb(); System.out.println(obj3+" "+obj4); System.out.println(obj4==obj3);//true,相同线程 System.out.println("____________"); new Thread(){ @Override public void run() { A a = new A(); Object obj5 = a.aa(); System.out.println("obj5:"+obj5); B b = new B(); Object obj6 = b.bb(); System.out.println("obj6:"+obj6); System.out.println(obj5==obj6);//true,相同线程 System.out.println(obj4==obj6);//false,相同线程 } }.start(); } } class A{ public Object aa(){ Object obj3=ThreadLocalDemo.getvalue(); return obj3; } } class B{ public Object bb(){ Object obj4=ThreadLocalDemo.getvalue(); return obj4; } }
ThreadLocal解决多线程程序的并发问题,解决数据库事务的处理
我们在数据库dao层中,难免会遇到不同的事务,但是不同事物之间怎么解决并发问题呢。怎么保证一个用户拿到的是同一个Connection对象呢?那么必须使用ThreadLocal来解决了,下面是我改进了connection工具类package cn.hncu.pubs; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.util.ArrayList; import java.util.List; import java.util.Properties; public class ConUtil { private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>(); //引入ThreadLocal来操纵同一个con对象,防止事物提交不一致的情况 private static List<Connection> list=new ArrayList<Connection>();//con连接池 private static final String FILE_NAME="jdbc.properities"; private static final int NUM=3; static{ Properties p=new Properties(); try { p.load(ConUtil.class.getClassLoader().getResourceAsStream(FILE_NAME));//用配置文件加载 String user=p.getProperty("username"); String url=p.getProperty("url"); String password=p.getProperty("password"); String driver=p.getProperty("driver"); Class.forName(driver); for(int i=0;i<NUM;i++){ final Connection con=DriverManager.getConnection(url, user, password); Object objCon=Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("close")){ synchronized (ConUtil.class) { list.add((Connection) proxy); tl.set(null);//设为空,不能少,防止不同用户拿到同一个con ConUtil.class.notify(); } return null; } return method.invoke(con, args); } }); list.add((Connection)objCon); } } catch(Exception e) { e.printStackTrace(); } } synchronized public static Connection getCon(){ Connection con=tl.get();//从ThreadLocal中拿到一个con if(con==null){ if(list.size()<=0){ try { ConUtil.class.wait(); // tl.set(getCon());//不能放在这里,因为第一次拿不到 } catch (InterruptedException e) { e.printStackTrace(); } } con=list.remove(0); tl.set(con);//吧con放入ThreadLocal中 } return con; } public static void main(String[] args) { System.out.println(getCon()); } }
详细使用,请参考mysql笔记8——MVC项目
相关文章推荐
- 如何设置客户端每次发送请求的时候,保证都是新建一个http连接,而不是和上次的连接用同一个?
- 一个TCP端口最多可以同时连接多少个客户端呢?
- Socket编程服务器和客户端(多个客户端可以同时连接一个服务器的同一端口)
- oracle分布式处理时报“ORA-02041: 客户数据库未开始一个事务处理”解决办法 - z
- PRO*C 函数事例 1 -- 数据库连接、事务处理
- MVC框架——学生信息管理系统(多表,多事务如何处理,一个用户如何共用一个Connection连接)
- 一个关于php使用pdo方式进行数据库连接和处理的类
- 关于脏数据比如说,有两个用户A,B同时操作数据库,A开始了一个事务,修改了某行,但还未提交,这个时
- ThreadLocal为每个线程生成一个connection数据库连接对象
- 遭遇Ora-02041:客户端数据库未启动一个事务,好在摆平了
- 关于“ORA-02041: 客户数据库未开始一个事务处理”
- 处理数据库镜像问题的一个案例——数据库主体与镜像断开连接
- ORA-02041: 客户数据库未开始一个事务处理 .NET 连接低版本ORACLE时需要注意的问题
- JDBC应用程序连接数据库--事务处理
- 如何处理客户端连接数据库?
- Socket编程服务器和客户端(多个客户端可以同时连接一个服务器的同一端口)
- 一个简单的跨域跨数据库事务处理架构
- 代码调用DruidDataSource来管理conn连接,同时声明了ThreadLocal对象来保存每次线程请求所获取的连接,这样可以避免每个new一个JDBC
- 数据库事务提交方法和怎样拿到一个insert语句中自动生成的值
- 正好整理了一下,自己做了个连接数据库的组件,支持SQLSERVER,ACCESS,ORACLE,FoxPro,MySql,IBM DB2,DBF等数据库,并且支持事务处理