gpt4 book ai didi

java - 在迭代器内的线程内删除集合的元素

转载 作者:行者123 更新时间:2023-11-30 03:32:18 24 4
gpt4 key购买 nike

我有这个循环:

for (Iterator<Socket> it = collection.iterator(); it.hasNext();) {
Object obj = it.next();
new Thread( () -> {
if(myCondition(obj)){
it.remove();
}
}).start();
}

有时它可以工作,但有时我在调用 it.remove(); 时会收到 java.lang.IllegalStateException有安全的方法吗?

---更新---

我需要在服务器上运行的代码中执行此操作,该代码从许多客户端套接字接收连接。这段代码时不时地执行一些查询,每次执行查询时,结果都会发送到所有连接的套接字。因此,对于每个套接字,我创建一个新线程来执行此操作。我试图从列表中删除的是关闭的套接字。

这是我的服务器如何工作的示例:

public class SocketServidor {
static ServerSocket serverSocket;
static List<Socket> socketsConectados = new ArrayList<>();

public static void main(String[] args) throws Exception {
serverSocket = new ServerSocket(5963);

new Thread( ()-> {
lacoConexao:
while(true) {
try {
socketsConectados.add(serverSocket.accept());
} catch (IOException ex) {
Logger.getLogger(SocketServidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();

lacoMensagens:
while(true) {
int valor = (int) (Math.random() * 3) + 1;
lacoIterators:
for (Iterator<Socket> it = socketsConectados.iterator(); it.hasNext();) {
Socket socket = it.next();
new Thread( () -> {
try {
if(socket.isClosed()) {
return;
}
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println("Você acabou de ganhar R$ "+new DecimalFormat("###,##0.00").format(valor)+" às "+new SimpleDateFormat("HH:mm:ss").format(new Date())+"!");
if(out.checkError()){
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
System.out.println("Sockets conectados: "+socketsConectados.size());
Thread.sleep(valor*1000);
}
}
}

最佳答案

您应该阅读有关线程安全的更多信息。我可以告诉您要在代码中修复哪些内容,但是在您正确理解并发性之前,您每次编写一行代码都会不断添加错误...

你应该:

  • 使用线程安全列表,例如 List<Socket> socketsConectados = new CopyOnWriteArrayList<>();
  • 使用线程池而不是为每个套接字创建一个线程:ExecutorService executor = Executors.newCachedThreadPool();
  • 将发送消息的任务提交到线程池,而不是手动创建线程
  • 您使用的那些标签也很令人困惑,它们应该用于从外部循环中中断 - 如果您只想注释代码,请使用注释!
<小时/>

作为引用,代码可能如下所示:

public class SocketServidor {
static ServerSocket serverSocket;
private static final ExecutorService executor = Executors.newCachedThreadPool();
private static final List<Socket> sockets = new CopyOnWriteArrayList<>();

public static void main(String[] args) throws Exception {
serverSocket = new ServerSocket(5963);
new Thread(SocketServidor::acceptSockets).start();
sendMessages();
}

private static void acceptSockets() {
while (true) {
try {
sockets.add(serverSocket.accept());
} catch (IOException ex) {
Logger.getLogger(SocketServidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

private static void sendMessages() throws InterruptedException {
while (true) {
int valor = (int) (Math.random() * 3) + 1;
for (Socket socket : sockets) {
executor.submit(() -> {
if (socket.isClosed()) sockets.remove(socket);
else sendMessage(socket, valor);
});
}
System.out.println("Sockets conectados: " + sockets.size());
Thread.sleep(valor * 1000);
}
}

private static void sendMessage(Socket socket, int valor) {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println("Você acabou de ganhar R$ " + new DecimalFormat("###,##0.00").format(valor) + " às " + new SimpleDateFormat("HH:mm:ss").format(
new Date()) + "!");
if (out.checkError()) {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

关于java - 在迭代器内的线程内删除集合的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28741247/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com