在Java线程中同步

时间:2010-01-01 15:32:31

标签: java thread-safety

我的程序是连接到多个服务器的客户端。我将连接对象保存到静态地图对象中的所有服务器:

  

server1 - >连接1
  server2 - >连接2
  serverN - > connectionN

public class CacheConnection {

    private final static Map cacheConnection = new HashMap();

    public static void add(String serverName, Socket sock) {
        synchronized (cacheConnection) {
            cacheConnection.put(serverName, sock);
        }
    }

    public static Socket get(String serverName) {
        return (Socket) cacheConnection.get(serverName);
    }

    ..
}

我有很多线程从这个地图获取连接以与服务器通信。如何确保连接一次只能由一个线程使用?

例如,我想确保线程1和线程2不能同时使用连接1.

2 个答案:

答案 0 :(得分:3)

我不完全确定,你想要什么。我假设你想保证一次只有一个线程访问一个特定的服务器。

如果您的连接类似于套接字,那么您可以将其用作synchronization statement中的锁:

private void send(Connection c, Data d) {
  synchronized (c) {
    // for each connection object, only one thread may be inside this block.
    // all other threads wait until the thread currently in this block exits it.
    c.send(d);
  }
}

// somewhere else ...

Data data = determineDataToSend()
Connection connection = map.get(key);
send(connection, data)

您也可以将逻辑放入装饰器中进行连接。如果您的连接有多个发送或接收方法(例如,因为您使用更高的抽象级别,如RMI),这将非常有用:

public interface PowerfulConnection {
  public void doA();
  public int doB(ParameterForB param);
}

public class ConnectionImpl implements PowerfulConnection {
   // handles the actual connection
}

/**
 * This method is a decorator for PowerfulConnection that synchronizes all method accesses.
 */
public class SynchronizedConnection implements PowerfulConnection {
  private PowerfulConnection target;

  public SynchronizedConnection(PowerfulConnection target) {
    if (target == null) throw new NullPointerException();
    this.target = target;
  }

  public synchronized void doA() {
    target.doA();
  }

  public synchronized int doB(ParameterForB param) {
    return target.doB(param);
  }
}

如果您正在使用装饰器方法,那么您唯一需要更改的是实例创建。而不是:

private void connect(key, connectionParams) {
  map.put(key, new ConnectionImpl(connectionParams));
}

使用

private void connect(key, connectionParams) {
  map.put(key, new SynchronizedConnection(new ConnectionImpl(connectionParams)));
}

答案 1 :(得分:0)

或者,在您的初始示例中,get方法可以从地图中删除连接。当然,这意味着客户端必须确保(可能在finally块中,在完成后再次调用add)

然后等待并通知循环客户端何时进入请求连接,并且它不存在。