- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我在我的应用程序中遇到了一些锁定问题,其中包含如下几个类:
public interface AppClient {
void hello();
}
public class Client implements AppClient {
public synchronized static AppClient getInstance() {
return instance;
}
public void hello() {
System.out.println("Hello Client");
}
private final static class InnerClient implements AppClient {
public void hello() {
System.out.println("Hello InnerClient");
}
}
private static AppClient instance;
static {
instance = new InnerClient();
doSomethingThatWillCallClientGetInstanceSeveralTimes();
}
}
public class Application {
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
// ...
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
}
在 doSomethingThatWillCallClientGetInstanceSeveralTimes() 方法中,它会做很多初始化工作,涉及很多类,并在初始化过程中多次循环调用 Client.getInstance 静态方法(我知道这不好,但是,这是遗留代码库持续 20 多年)。
这是我的问题:
1)我以为在类Client初始化完成之前,只有第一个触发类Client初始化的线程才能访问Client.getInstance方法,因为JVM会在类初始化完成之前在Client.class对象上进行同步。我阅读了相关主题的 JLS 并得出了这个结论(第 12.4.2 节,详细的初始化过程,http://java.sun.com/docs/books/jls/third_edition/html/execution.html)。
2) 但是,这不是我在真实环境中看到的行为。比如有3个线程调用了Client.getInstance(),thread-1触发了Client.class的初始化,在doSomethingThatWillCallClientGetInstanceSeveralTimes()方法中多次调用了Client.getInstance()。而在doSomethingThatWillCallClientGetInstanceSeveralTimes()方法完成之前,thread-2获取了Client.class对象的锁(这怎么可能?但是确实发生了),然后进入了Client.getInstance方法(因为这个方法是静态同步方法) .由于某种原因,线程 2 无法返回“实例”(我猜它正在等待 Client.class 完成其初始化)。同时,thread-1 无法继续执行,因为它仍然需要在 doSomethingThatWillCallClientGetInstanceSeveralTimes() 中调用 Client.getInstance,并且由于它属于 thread-2,因此无法获取锁。 Threaddump 告诉我线程 2 处于 RUNNABLE 状态,线程 1 处于 BLOCKED 状态,等待线程 2 拥有的锁。
我只能在 Windows 的 64 位 Java 6u23 JVM 中重现此行为,无法在 32 位 Java 6 JVM + Windows 环境中重现。有人能告诉我我在这里想念什么吗?这种代码是不是注定会产生这样的锁,如果是,又是怎么来的呢?我对这部分的 JLS 的理解不正确吗?还是 JVM 问题?任何帮助表示赞赏。谢谢。
最佳答案
对我来说,这看起来像是一个错误。当一个线程正在调用静态 block 时,没有其他线程应该能够访问它。该错误可能是另一个线程可以在初始化完成之前获取该类的锁。 :(
我建议您构建代码,这样您就不需要在启动时进行这种锁定。听起来确实很复杂。例如在您的示例中,客户端不需要扩展客户端,并且可以在其声明的行上初始化实例。我会考虑以下结构。
enum Client implements AppClient {
INSTANCE;
public void hello() {
System.out.println("Hello Client");
}
}
您可以使 Client 可变或使用委托(delegate),这样它就不会暴露它可以更改状态(或实现)的事实
关于java - 静态初始化程序和静态同步方法锁定问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4612492/
我刚刚用 java-swing 为我写了一个桌面时钟,我希望每次登录时该时钟都运行。 为此,我将我的 jar 文件添加到 start 文件夹,我让时钟开始运行。 但我的问题是 - 任务栏中显示的图标允
我正在尝试编写一个程序来检查用户是否上传了新视频。我想让它成为一项后端工作,不断检查用户最近的视频,然后使用我的应用程序向我的用户发送推送。有关于这个问题的任何文档或示例代码吗?我完全不知道从哪里开始
我正在为我的 Raspberry Pi 编写一个程序,该程序由两个主要部分组成: 使用 Spotify-API“Libspotify”搜索音乐并播放音乐的 C 程序。 一个在 apache2 We
我做了一个C++生成命令行并将命令转发给它的程序。目前,我正在将 cmd 控制台的输出发送到一个文件,并在我的 C++ 程序中读取它。但我想让它与管道一起工作。 是否可以从 Windows cmd 行
是否可以使用 C 程序和 malloc 找出处理器的页面大小?而不是使用 sysconf() 调用? 最佳答案 如果你可以#include一些linux内核头文件,你可以在中找到宏PAGE_SIZE
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我想实现一个算法: 从 Ruby on Rails 应用程序获取数据库对象作为输入, 对输入执行计算, 根据计算查询 Rails 数据库, 并根据查询生成一组有序结果。 我将用 C(也许是 Objec
我今天的任务是创建一个 Python 脚本(例如 A.py),它可以执行以下操作: 启动 C 程序(例如 CProg)并传递一些参数 启动另一个 Python 脚本(例如 B.py)并传递其他参数 加
我有一个在后台运行的 .NET 程序,需要创建一个可以与该程序通信的 Windows Shell 扩展。起初我以为我会在 .NET 中创建我的 Shell Extension,并使用 IpcServe
Python 程序做前端工作,C 程序做后端工作。它们中的每一个都是一个单独的过程。 Python 进程充当主进程,向 C 进程发送信号和事件。 C 进程生成统计信息、计数器和信息,这些信息被发送回
如何与 shell 脚本共享 C 头文件? shell 脚本通过命名管道与 C 程序通信。让我们假设 C 头文件中定义的枚举 SAMPLE_ONE 由 C 程序写入管道。 shell 脚本从管道中读出
我有一些客户/候选人提示我的程序不能在他们的 Windows 7 64 位版本上运行(已通过屏幕截图确认)。错误很奇怪,例如: in the trial version i am getting a
这个问题在这里已经有了答案: Why SDL defines main macro? (2 个答案) 关闭 7 年前。 我在 Windows 操作系统下使用 QT Creator 的简单程序中使用
我的导师给了我们一个基本的 C shell 来扩展,我目前正在努力让 shell 在用户在命令行中输入“cd [directory]”时更改目录。我已经得到它来停止段错误,但它不会更改目录。谁能告诉我
我以前有过这个工作,但我使用的是指针。 getenv() 不断崩溃,所以我使用 sprintf() 复制了结果。现在我想用 : 删除并只打印第一次出现的地方。请帮忙! #include #inclu
你好,我第一次使用 C primer plus book 学习 C,然后在第 16 章关于 C11 标准的 _Generic 我在 Eclipse c/c++ 中编写了一个程序并构建它产生了 8 个错
我正在尝试从另一个 C 程序执行 python 程序,其中 py 脚本的返回值为 int array[3] 我可以从 python 退出代码中获取这个数组吗?? 编辑:如果问题不清楚,我可以将 pyt
// The countChicken() method should count the number of occurrences of the word chicken (or some oth
我已经通过 ZMQ 使用同一类成功地从 C# 和 C++ 程序传输数据,其中 C++ 类是数据定义,编译器幸运地将字节数组屏蔽到类。 我如何在 C# 和 Node.js 程序之间做同样的事情?我认为他
任何人都可以为我指明有关 makefile 如何工作以及如何使用 eclipse 从头开始基本程序的好教程的方向吗?我正在为 fedora 和 C++ 使用 eclipse 3.4.1 版。提前致
我是一名优秀的程序员,十分优秀!