英文:
Reliable way to unlock locked synchronize block
问题
以下是翻译好的内容:
系统偶尔会在同步块上抛出一个严重错误,而且有一个 try-catch,理论上应该启动一个线程的“解锁”过程,但实际上没有触发。因此,我可以得出结论,系统内部没有将其视为异常。是否有合理的方法来处理这种锁呢?
考虑来自 board.jsp
的以下代码片段:
account = Account.get(accountID);
Object synch = account;
if (synch == null) {
%>没有账户。<%;
return;
}
try {
synchronized (synch) {
....
}
} catch (Exception e) {
....
} finally {
....
}
示例输出:
严重错误:计划任务未运行!
2020年4月7日 下午4:59:36 ExecLauncher:execLauncher run
严重错误:---------------------
线程为:“http-bio-8080-exec-18” Id=122,被“http-bio-8080-exec-7” Id=38 拥有,位于 com.main.Account@5a0b8133 上阻塞
在 org.apache.jsp.realtime.board_jsp._jspService(board_jsp.java:192) 处被阻塞,阻塞在 com.main.Account@5a0b8133 上
在 org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) 处
感谢查看
英文:
Occasionally the system throws a SEVERE error on the synchronized block and there is a try-catch which should, in theory, initiate a thread 'unlock' process however this isn't triggered. I, therefore, can conclude that this is not treated as an exception within the system. Is there a reasonable way of handling said lock?
Consider the following code from board.jsp
:
account = Account.get(accountID);
Object synch=account;
if(synch == null) {
%>No account.<%
return;
}
try {
synchronized(synch) {
....
}
} catch (Exception e) {
....
} finally {
....
}
example dump
SEVERE: Scheduled tasks not running!
Apr 07, 2020 4:59:36 PM ExecLauncher:execLauncher run
SEVERE: ---------------------
Thread is: "http-bio-8080-exec-18" Id=122 BLOCKED on com.main.Account@5a0b8133 owned by "http-bio-8080-exec-7" Id=38
at org.apache.jsp.realtime.board_jsp._jspService(board_jsp.java:192)
- blocked on com.main.Account@5a0b8133
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
Thanks for looking
答案1
得分: 0
你可以尝试这个,通过使用可重入锁(Reentrant locks)来明确地进行锁定和解锁,从而获得更多的控制。
account = Account.get(accountID);
Object synch = account;
Lock lock = new ReentrantLock();
if (synch == null) {
%>没有账户。<%
return;
}
try {
lock.lock();
/* 在原来的同步块中执行的实际代码 */
} catch (Exception e) {
// ...
} finally {
lock.unlock(); // 这将起作用
}
英文:
You can try this out, you will get more control to lock and unlock explicitly using Reentrant locks.
account = Account.get(accountID);
Object synch=account;
Lock lock = new ReentrantLock();
if(synch == null) {
%>No account.<%
return;
}
try {
lock.lock();
/* Your actual code which you were executing in
the synchronized block */
} catch (Exception e) {
....
} finally {
lock.unlock(); // this will work
}
答案2
得分: 0
这不是一个异常,而是在说明线程“http-bio-8080-exec-18”无法执行,因为它尝试进入同步(synch)块。它无法进入此块,因为监视器当前由线程“http-bio-8080-exec-7”持有。
因此,首要任务是找出为什么“http-bio-8080-exec-7”没有释放监视器。这可能仅是性能问题,太多的线程正在尝试并行执行此部分事务。或者线程可能挂起了。您可以通过生成线程转储来进行分析:
要生成线程转储,请转到您的Java安装的bin文件夹。有一个称为jps的工具(在Windows上是jps.exe)。执行此命令,您将看到一个数字(进程ID)和程序的名称。找到您的程序并执行jstack [pid]。jstack也位于您的Java安装的bin文件夹中。
然后,您将看到程序中每个线程正在做什么,以及当前拥有监视器的线程正在做什么。
还有一种方法可以等待特定时间来尝试获取锁定。我不太确定这是否能解决您的问题,但为了完整起见,我在这里解释一下。与tryLock一起使用可重入锁:
if (lock.tryLock(long timeout, TimeUnit unit)) {
try {
// ... 方法体
} finally {
lock.unlock();
}
} else {
// 在给定的时间内无法获取锁定
}
英文:
This is not an exception but rather it says that the Thread "http-bio-8080-exec-18" can not execute because it tries to enter the synchronized(synch) block. It can not enter this block because the monitor is currently held by the thread "http-bio-8080-exec-7".
So the first thing is to find out why "http-bio-8080-exec-7" does not release the monitor. This might simply be a performance problem, to many threads are trying to execute tissecition in parallel. Or the thread might be hanging. You can analyze this by generating a thread dump:
To generate a thread dump go to the bin folder of your java installation. There is a tool called jps (jps.exe on windows) Execute this, you will see a number (the pid) and a name of a program. Find your program and execute jstack [pid]. jstack is also in the bin folder of your Java installation.
You then will see what every thread is doing in your program, and what the thread with is currently owning the monitor is doing.
There is a way to wait only a specific time to try to aqcuire a lock. I am not quite sure if this solves your problem but to be complete here it is. Use a reentrant lock together with tryLock:
if( lock.tryLock(long timeout,
TimeUnit unit))
{ try {
// ... method body
}
finally {
lock.unlock()
}
}
else {
// lock could not be acquired at the given time
}
专注分享java语言的经验与见解,让所有开发者获益!
评论