假设我有一个班级:
public final class Server {
private final ArrayList<ServerConnection> connections;
private ServerConnection pending;
private Thread connector;
public Server() {
connections = new ArrayList<>();
connector = new Thread(() -> {
while (true) {
pending = new ServerConnection();
pending.waitForConnection();
//Could be adding while another thread is iterating.
connections.add(pending);
}
}, "Connection Establisher");
connector.setDaemon(true);
connector.setPriority(Thread.MIN_PRIORITY);
connector.start();
}
//Anyone with a refrence to this object can access connections.
public ArrayList<ServerConnection> getConnections() {
return connections;
}
}
在添加对象时,如何确保connections
未被使用?我想过在线程中使用synchronized (connections) {...}
块但是根据我对synchronized
块的了解,对connections
的所有非线程安全引用都必须在同步块中。有什么方法可以确保所有对connections
的非线程安全访问都是同步的吗?
答案 0 :(得分:0)
使getConnections
方法同步是不够的,因为一旦调用者获得对列表的引用,它就可以随意执行任何操作,包括线程不安全操作。
一些简单的步骤可以使您的代码更加健壮:
简单的重写可能看起来像下面的代码(它当然可以改进) - 检查注释。请注意,如果waitForConnection
也适当地对中断作出反应,例如通过抛出InterruptedException
,它会更好。
public final class Server {
//us a thread safe list
private final List<ServerConnection> connections = new CopyOnWriteArrayList<>();
//make the thread final
private final Thread connector;
public Server() {
connector = new Thread(() -> {
//provide a mechanism to stop the thread: exit on interruption
while (!Thread.currentThread().isInterrupted()) {
ServerConnection pending = new ServerConnection();
pending.waitForConnection();
//Could be adding while another thread is iterating.
connections.add(pending);
}
}, "Connection Established");
//Note that the priority may be ignored at runtime
connector.setPriority(Thread.MIN_PRIORITY);
}
public void start() {
connector.start();
}
//to stop the thread, interrupt it
public void stop() {
if (!connector.isAlive()) throw new IllegalStateException("The server is not started");
connector.interrupt();
}
//don't return the list but an unmodifiable view of the list
public List<ServerConnection> getConnections() {
return Collections.unmodifiableList(connections);
}
}