作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有这个循环:
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/
我是一名优秀的程序员,十分优秀!