我试图使Clients
类单例,但它不工作。这是我的类:
public class Clients {
private static Clients instance = null;
private ArrayList<Client> cList;
private Clients() {
cList = new ArrayList<Client>();
}
public static Clients getInstance() {
if (instance == null) {
System .out.println("created");
instance = new Clients();
}
return instance;
}
public static ArrayList<Client> getcList() {
return getInstance().cList;
}
public static void setcList(ArrayList<Client> cList) {
getInstance().cList = cList;
}
}
我在两个不同的类中获得这个实例(都有自己的main函数)。在一个类中获得它的实例后,我在另一个类中获得它,但这两个类仍在执行。
无论何时实现单例,getInstance()
方法都应该是线程安全的。
。
public static synchronized Clients getInstance()
…还是…
private static final Object INSTANCE_LOCK = new Object();
public static Clients getInstance() {
synchronized(INSTANCE_LOCK) {
if(instance == null) instance = new Clients();
}
return instance;
}
当然,如果实际上是在两个不同的程序中执行这段代码,而不是在两个不同的线程中执行,那么就会有两个实例。我假设是前者,因为后者使你的问题变得毫无意义。
我想我应该解释为什么这是荒谬的。
当您使用main(String[] args)
方法执行Java程序时,所有的类都被加载到JVM中。如果您随后执行另一个程序,您将获得另一个JVM和所有相关类的另一个"副本"。这样,您就有了两个单独的单例对象——每个程序一个。两者之间不共享类
您提到两个类"都有自己的main",所以我假设您有两个独立的程序。
长话短说,两个程序之间并不真正共享数据。单例类将确保在单个程序中只有一个对象的实例,但是两个程序仍然是完全相互独立的,不能以这种方式共享数据。
即使只有一个带有"main"的类并且只运行两次,也会出现这种情况。
如果你想在程序之间像这样共享数据,你有很多很多的选择,但其中一些是:
- 看看你是否可以把两个独立的程序合并成一个。你真的需要两个程序吗?
- 使用数据库来存储数据,MySQL和SQLite是两个简单的选择。
- 一个程序可以向文件写入数据,另一个程序可以读取数据。 从一个程序到另一个程序发送数据有很多其他的选择,比如套接字(已经存在无数的网络协议,加上你可以自己推出),特定于平台的东西,如Windows上的命名管道,共享内存等。查看"java ipc"(进程间通信——这些是允许两个程序相互通信的通用技术)的Google结果。
您可以像Jeff Gohlke所说的那样使用上面的同步块,但是您可能还想考虑使用锁。
锁最好的地方是synchronized关键字不提供公平性,而我们可以在创建ReentrantLock对象时将公平性设置为true,以便等待时间最长的线程首先获得锁。
// Fairness set to false is faster than a synchronized block.
private static final ReentrantLock rlock = new ReentrantLock(false);
public static final Clients getInstance() {
rlock.lock();
try {
System.out.printf("[Thread %s] Clients.getInstance()%n",
Thread.currentThread().getName());
if (instance == null) {
instance = new Clients();
}
return instance;
} finally {
rlock.unlock();
}
}
你可以通过执行
来解决很多问题 private static Clients instance = new Clients()
。
无需担心get实例中的锁定习惯用法。除非你正在构建的类的构建成本很高,否则做这种惰性实例化是没有意义的。
说到这里,我也不确定我是否喜欢cList的getter和setter。我更喜欢这些是你正在创建单例的类的实例方法,所以你会做(例如)
Clients clients = Clients.getInstance();
clients.getcList();
并且,如果这是一个多线程环境,那么你必须意识到setter可能会影响其他已经有对单例对象引用的线程。