0

我想在 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);
      }
    }
  }

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

[更新]

这应该有望说明问题:

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

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

4

2 回答 2

0

@Lock(LockType.WRITE) locks all methods in the singleton bean until the called method has completed even if the caller has moved on via @Asynchronous.

This is the correct behaviour if you think about it - concurrency problems can happen from other method calls to the bean if processing is still in progress.

The way to get around this is to set @ConcurrencyManagement(ConcurrencyManagementType.BEAN) on your singleton to handle concurrency and locking of access to the connection yourself.

Have a look at http://docs.oracle.com/javaee/6/tutorial/doc/gipvi.html#indexterm-1449 for an introduction.

于 2013-06-05T06:45:12.107 回答
-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);
      }
    }
  }
于 2013-06-03T10:20:39.097 回答