SessionHolder

本文深入探讨SessionHolder作为Session封装的实现细节,重点解释其如何通过Collections.synchronizedMap确保线程同步安全,以及同步Map与普通Map的异同。同时揭示了同步Map在并发操作中的局限性,并通过实例演示了可能导致的并发问题。

SessionHolder是session的封装产品。

public class SessionHolder extends ResourceHolderSupport {

	private final Map<Object, Session> sessionMap = Collections.synchronizedMap(new HashMap<Object, Session>(1));
首先这里sessioniMap是SessionHolder的一个属性.Collections.synchronizedMap(new HashMap<Object, Session>(1))是把session封装,是为了线程同步安全。我们看

Colleactions这个类

    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
	return new SynchronizedMap<K,V>(m);
    }

上面该类的synchronizedMap方法是传一个Map进去,返回出来的不过是同步的,

	SynchronizedMap(Map<K,V> m) {
            if (m==null)
                throw new NullPointerException();
            this.m = m;
            mutex = this;
        }

传到SynchronizedMap里面来,封装成同步的Map,这里mutex=this,为什么直接不用this,因为在同步的时候synchronized()里面不能传this,只能传变量,

public int size() {
	    synchronized(mutex) {return m.size();}
        }
	public boolean isEmpty(){
	    synchronized(mutex) {return m.isEmpty();}
        }
	public boolean containsKey(Object key) {
	    synchronized(mutex) {return m.containsKey(key);}
        }.............省略

也就是差不多重写了HashMap类的所以方法,但是把方法都同步了.还有就是你知道当前这个Map的方法同步了,但是调用Map里面的方法则不同步,map.keySet().size()则不同步。

这其实也相当了HashTable一样,我们都知道HashTable是线程安全的,而HashMap是非线程安全的,效率高。

从HashTable的源码中可以看出HashTable只是在定义的时候把方法都定义成同步的了,和这个Collections.synchronizedMap差不多,这个Collections只不过把Map封装了下

但是它的效率也是非常低的,而且也有一定的缺陷:

例如下面这段代码:

if(map.containsKey("key")){

map.remove("key");

}

当第一个人调用if里面的时候查出来为true,跑remove方法,随之在这时有第二个人来调用,也跑if里面,但是第一个人要删除这个key时,会报错!由于这些方法时同步的,第二个人在访问containKey,第一个人则不能访问,删除时肯定找不到,这就是问题所在。




<== 21:27:50.070 ERROR --- [ RetryCommitting_1_1] i.s.s.s.d.l.DataBaseDistributedLocker : execute acquire lock failure, key is: RetryCommitting ==> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'zy-seata.distributed_lock' doesn't exist at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2034) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.getDistributedLockDO(DataBaseDistributedLocker.java:211) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.acquireLock(DataBaseDistributedLocker.java:115) at io.seata.server.session.SessionHolder.acquireDistributedLock(SessionHolder.java:376) at io.seata.server.session.SessionHolder.distributedLockAndExecute(SessionHolder.java:398) at io.seata.server.coordinator.DefaultCoordinator.lambda$init$6(DefaultCoordinator.java:493) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:750) <== 21:27:50.070 ERROR --- [ TxTimeoutCheck_1_1] i.s.s.s.d.l.DataBaseDistributedLocker : execute acquire lock failure, key is: TxTimeoutCheck ==> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'zy-seata.distributed_lock' doesn't exist at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2034) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.getDistributedLockDO(DataBaseDistributedLocker.java:211) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.acquireLock(DataBaseDistributedLocker.java:115) at io.seata.server.session.SessionHolder.acquireDistributedLock(SessionHolder.java:376) at io.seata.server.session.SessionHolder.distributedLockAndExecute(SessionHolder.java:398) at io.seata.server.coordinator.DefaultCoordinator.lambda$init$8(DefaultCoordinator.java:501) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:750) <== 21:27:51.072 ERROR --- [ RetryRollbacking_1_1] i.s.s.s.d.l.DataBaseDistributedLocker : execute acquire lock failure, key is: RetryRollbacking ==> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'zy-seata.distributed_lock' doesn't exist at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2034) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.getDistributedLockDO(DataBaseDistributedLocker.java:211) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.acquireLock(DataBaseDistributedLocker.java:115) at io.seata.server.session.SessionHolder.acquireDistributedLock(SessionHolder.java:376) at io.seata.server.session.SessionHolder.distributedLockAndExecute(SessionHolder.java:398) at io.seata.server.coordinator.DefaultCoordinator.lambda$init$5(DefaultCoordinator.java:489) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:750) <== 21:27:51.072 ERROR --- [ RetryCommitting_1_1] i.s.s.s.d.l.DataBaseDistributedLocker : execute acquire lock failure, key is: RetryCommitting ==> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'zy-seata.distributed_lock' doesn't exist at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2034) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.getDistributedLockDO(DataBaseDistributedLocker.java:211) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.acquireLock(DataBaseDistributedLocker.java:115) at io.seata.server.session.SessionHolder.acquireDistributedLock(SessionHolder.java:376) at io.seata.server.session.SessionHolder.distributedLockAndExecute(SessionHolder.java:398) at io.seata.server.coordinator.DefaultCoordinator.lambda$init$6(DefaultCoordinator.java:493) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:750) <== 21:27:51.072 ERROR --- [ TxTimeoutCheck_1_1] i.s.s.s.d.l.DataBaseDistributedLocker : execute acquire lock failure, key is: TxTimeoutCheck ==> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'zy-seata.distributed_lock' doesn't exist at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2034) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.getDistributedLockDO(DataBaseDistributedLocker.java:211) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.acquireLock(DataBaseDistributedLocker.java:115) at io.seata.server.session.SessionHolder.acquireDistributedLock(SessionHolder.java:376) at io.seata.server.session.SessionHolder.distributedLockAndExecute(SessionHolder.java:398) at io.seata.server.coordinator.DefaultCoordinator.lambda$init$8(DefaultCoordinator.java:501) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:750) <== 21:27:51.072 ERROR --- [ AsyncCommitting_1_1] i.s.s.s.d.l.DataBaseDistributedLocker : execute acquire lock failure, key is: AsyncCommitting ==> com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'zy-seata.distributed_lock' doesn't exist at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2034) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.getDistributedLockDO(DataBaseDistributedLocker.java:211) at io.seata.server.storage.db.lock.DataBaseDistributedLocker.acquireLock(DataBaseDistributedLocker.java:115) at io.seata.server.session.SessionHolder.acquireDistributedLock(SessionHolder.java:376) at io.seata.server.session.SessionHolder.distributedLockAndExecute(SessionHolder.java:398) at io.seata.server.coordinator.DefaultCoordinator.lambda$init$7(DefaultCoordinator.java:497) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:750) <==
最新发布
09-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值