【问题标题】:Singleton class accessed from another class从另一个类访问的单例类
【发布时间】:2012-10-17 17:11:01
【问题描述】:

我有一个场景,我必须连接到虚拟中心并获取数据。我已经实现了一个单例类,因此两个线程不能同时访问 VC,因为它存在并发访问问题。我的代码如下:

public class Connector {    
private static Connector instance ;    
private Connector(String urlStr, String username, String password) {
    connect(urlStr, username, password);
}    
public static synchronized Connector getInstance(String urlStr, String username, String password) {
    if (instance == null){
        instance = new Connector(urlStr,username,password);
        System.out.println("creating instance");
    }
    return instance ;
}   
public void connect(String urlStr, String username, String password) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    try {
        //code to connect to VC
        }

    } catch (RuntimeException e) {
        connectException = e;
    } finally {
        Thread.currentThread().setContextClassLoader(cl);
    }
}


public void disconnect() throws RuntimeFault, RemoteException {
    //code for disconnect
    }
}

}

我通过以下方式从另一个类中调用它:

Connector c = Connector.getInstance(dburl, dbuser, dbpass);
c.connect(dburl, dbuser, dbpass);
//code for getting data
c.disconnect();

现在,如果我有 2 个同时请求从虚拟中心获取数据,其中一个请求失败,说“会话未通过身份验证”。 你能帮助我们更好地处理这个问题吗? 并且由于始终使用相同的实例,如果它是不同的虚拟中心,我们如何区分。

【问题讨论】:

标签: java multithreading singleton


【解决方案1】:

你的序列

  1. 连接
  2. 做事
  3. 断开连接

不是原子的,这意味着有可能

  1. 线程 1 连接
  2. 线程 2 连接
  3. 线程 1 做事
  4. 线程 1 断开连接
  5. 线程 2 尝试做某事但失败了。

构建您的类,以便客户端不会连接失败、断开连接失败或与另一个操作交错。

您的 API 可以允许想要使用连接的代码传入一个在连接时使用连接的对象,并返回使用该连接的结果:

 public interface ConnectionTask<T> {
   public T useConnection(Connection c);
 }

然后写一个 useConnection 而不是 getInstance 那样

 public synchronized <T> T useConnection(ConnectTask<T> c) {
   connect();
   try {
     return c.useConnection(this);
   } finally {
     disconnect();
   }
 }

并制作connectdisconnect private,这样客户就不会滥用它们。

【讨论】:

    【解决方案2】:

    在第一种方法中,您只保留对连接的独占访问权限。

    我建议你添加一个Lock,比如ReentrantLock,你在第一种方法中锁定并在释放连接时解锁。

    另一种方法是使用可能更安全的访问者模式。

    interface UsesConnector {
        public void useConnector(Connector connector);
    }
    
    public class Connector {
        private static final Connector connector = new Connector();
    
        public static synchronized void useConnector(String urlStr, String username, String password, UsesConnector usesConnector) {
             connector.connect(urlStr, username, password);
             try {
                 usesConnector.useConnector(connector);
             } finally {
                 connector.disconnect();
             }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-13
      • 2023-01-07
      • 2012-05-21
      • 1970-01-01
      • 2011-04-28
      • 2012-05-18
      • 1970-01-01
      相关资源
      最近更新 更多