如何使用异步单例bean处理并发

时间:2013-06-03 10:16:57

标签: java java-ee

我想在Java EE中实现一个单独的bean,它可以按需启动VPN连接。

因此我创建了一个类:

@Singleton
class VPNClient{
  private boolean connected;

  @Lock(LockType.READ)
  public boolean isConnected(){
    return this.connected;
  }

  @Asynchronous
  @Lock(LockType.WRITE)
  public void connect(){
    // do connect, including a while loop for the socket:

    while(true){
      // read socket, do stuff like setting connected when VPN successfully established
    }
  }
}

然后我有另一个bean,它需要VPN连接并尝试创建它:

  class X {
    @Inject 
    VPNClient client;

    private void sendStuffToVPN(){

      // call the async connect method
      client.connect();

      // wait for connect (or exception and stuff in original source)
      while(!client.isConnected()){

        // wait for connection to be established
        Thread.sleep(5000);
      }
    }
  }

我现在的问题是,由于connect方法,在连接被销毁之前永远不会结束,它所具有的写锁定将阻止对isConnected()的所有读取。

[更新]

这应该有希望说明问题:

  • 线程1(Bean X)调用线程2(Singleton Bean VPNClient).connect()
  • 现在在单例bean VPNClient上有一个无限的写锁定。但因为该方法被称为异步。线程1继续:
  • 线程1(Bean x)尝试调用线程2(VPNClient.isConnected()),但必须等待释放写锁(以connect()开头)。
  • 然后J2EE容器抛出一个javax.ejb.ConcurrentAccessTimeoutException,因为它一直等到超时。

有没有一种好的模式可以解决这种并发问题?

2 个答案:

答案 0 :(得分:0)

@ Lock(LockType.WRITE)锁定单例bean中的所有方法,直到被调用的方法完成,即使调用者已经通过@Asynchronous进行了移动。

如果你考虑这是正确的行为 - 如果处理仍在进行中,则可以通过对bean的其他方法调用发生并发问题。

解决这个问题的方法是在你的单例上设置@ConcurrencyManagement(ConcurrencyManagementType.BEAN)来自己处理并发和锁定对连接的访问​​。

查看http://docs.oracle.com/javaee/6/tutorial/doc/gipvi.html#indexterm-1449的介绍。

答案 1 :(得分:-1)

试试这个。

 class X {
    private void sendStuffToVPN(){
      VPNClient client = new VPNClient();

      // call the async connect method
      new Thread(new Runnable(){
                    public void run()
                    {
                       client.connect();
                    }
      }).start();

      // wait for connect (or exception and stuff in original source)
      while(!client.isConnected()){

        // wait for connection to be established
        Thread.sleep(5000);
      }
    }
  }