gpt4 book ai didi

JavaServlet : How to instantiate thread and receive messages

转载 作者:行者123 更新时间:2023-12-02 07:05:38 26 4
gpt4 key购买 nike

我已经读过关于 Servlet Thread handling 的精彩文章.

我有以下问题:我想创建一个简单的 Servlet,它启动一个在第一个版本中生成随机消息的新线程,或者根据参数发送包含自上次请求以来生成的所有消息的响应。

我在浏览器站点上使用 JQuery AJAX 调用来处理带有超时的请求。

当我运行接收器调用时,我只收到自线程同时崩溃以来生成的第一条消息。看起来这将是一个线程安全问题,如上述文章中所述,但我可以准确地弄清楚。该日志为我提供了以下信息:

SEVERE: Exception in thread "Thread-75" 
SEVERE: java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at com.lancom.lsr.util.RandomMessageProducer.run(RandomMessageProducer.java:35)
at java.lang.Thread.run(Thread.java:722)

SEVERE: at java.lang.Object.wait(Native Method)
SEVERE: at com.lancom.lsr.util.RandomMessageProducer.run(RandomMessageProducer.java:35)
SEVERE: at java.lang.Thread.run(Thread.java:722)

这是我当前的 servlet 代码:

public class MyServlet extends HttpServlet { 
...
private RandomMessageProducer rmProducer;
private Thread rmpThread;
...

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<Integer, String> msg = new HashMap<Integer, String>();
Gson gson = new Gson();

String sDevs = request.getParameter("devices"); // Option 1
String sGetMsg = request.getParameter("rec_msg"); // Option 2
PrintWriter pw = response.getWriter();

// Request: Send information and run thread
if (sDevs != null && STATUS==0) {

/* Start a dummy producer */
rmProducer = new RandomMessageProducer();
rmpThread = new Thread( rmProducer )
rmpThread.start();

pw.print("{\"1\": \"Action started!\"}");
STATUS=1;
}
// Request: Receive messages
else if (sGetMsg != null) {
List<String> logs = rmProducer.getLogMsg();
for (String lmsg : logs) {
// Check if we can update the current Status
if (msg.equals("<<<FIN_SUCC>>>") || msg.equals("<<<FIN_ERR>>>")) {
STATUS=0;
}
msg.put(0, lmsg);
}
String json = gson.toJson(msg);
pw.print(json);
}
pw.close();
}
}

这是我的简单消息生产者线程:

public class RandomMessageProducer implements Runnable {

private Queue<String> msgQueue = new LinkedList<String>();

@Override
public void run() {
Random randomGenerator = new Random();
for (int idx = 1; idx <= 100; ++idx){
int randomInt = randomGenerator.nextInt(100);
msgQueue.add("Generated : " + randomInt);
try {
wait(500);
} catch (InterruptedException e) {
msgQueue.add("<<<FIN_ERR>>>");
e.printStackTrace();
}
}
msgQueue.add("<<<FIN_SUCC>>>");
}

public List<String> getLogMsg() {
List<String> res = new ArrayList<String>();
while (!msgQueue.isEmpty()) {
res.add( msgQueue.poll() );
}
return res;
}
}

请求执行时间为 1000 毫秒

你可能看出我的推理错误了吗?

非常感谢!

最佳答案

这里存在严重的线程安全问题。

首先,您正在使用 wait()当您只想睡几毫秒时。您应该使用Thread.sleep()反而。这将解决您的异常,但不会解决线程安全问题。

您有一个由多个线程并行使用的共享链表:随机生成器线程将消息存储在队列中,而 servlet 线程从队列中移出消息。因此,您应该使用并发集合(如 ConcurrentLinkedQueue),或者同步对链表的每次访问。我会使用并发集合。

最后,几个 servlet 线程读取并修改 rmpThreadrmProducer并行变量,没有任何类型的同步。 rmpThread 变量已写入,但从未读取,因此我将其改为局部变量。确保新写的rmProducer对于其他 servlet 可见,您需要同步其所有访问,方法是使用同步块(synchronized block)来写入和读取它,或者将其设置为 volatile ,或者将其包装到 AtomicReferece 中(这是我会做出的选择)。

所以 rmProducer 应该这样声明:

private AtomicReference<RandomMessageProducer> rmProducerRef = new AtomicReference<>();

要修改其值,您应该使用

rmProducerRef.set(rmProducer);

要得到它,你应该使用

rmProducerRef.get();

关于JavaServlet : How to instantiate thread and receive messages,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16145188/

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