【问题标题】:Singleton class is not working [closed]单例类不工作[关闭]
【发布时间】:2014-05-08 13:16:48
【问题描述】:

我正在尝试制作 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;
    }
}

我在两个不同的类中得到这个实例(都有自己的主要功能)。在一个类中获取它的实例后,我在另一个类中获取它,但两个 tiare 仍在执行。

【问题讨论】:

  • 您是否从多个线程访问?
  • 你想达到什么目的?
  • 另外,你提到两个类都有自己的 main 方法。这是否意味着您正在运行两个单独的程序来访问单例?如果是这样,单例不会超出特定的进程边界
  • 我很困惑。您在两个类中执行此操作,并且都有自己的主要功能;这是否意味着您正在编译和运行两个不同的程序?

标签: java singleton


【解决方案1】:

您可以像 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();
    }    
}

【讨论】:

  • 我以前从未见过有人使用&lt;kbd&gt; 作为用户链接。这看起来很酷。
  • 不知何故,我在 7 年后发现自己在这里,我看着答案,认为“嗯,用户链接的 kbd,有趣,而且看起来很酷”,然后当我发现我时有点好笑已经评论过了。我觉得……一致,哈哈。
  • @JasonC 不错……?
【解决方案2】:

你可以通过这样做来解决很多问题

private static Clients instance = new Clients()

无需担心 get 实例中的锁定习语。除非您正在构建的类的构建成本很高,否则进行这种惰性实例化是没有意义的。

话虽如此,我也不确定我是否喜欢 cList 的 getter 和 setter。我希望这些是你正在制作单例的类的实例方法,所以你会这样做(例如)

Clients clients = Clients.getInstance();
clients.getcList();

而且,如果这是一个多线程环境,那么您必须注意 setter 可能会影响已经引用了单例对象的其他线程。

【讨论】:

    【解决方案3】:

    您提到两个类“都有自己的主程序”,所以我假设您有两个独立的程序。

    长话短说,两个程序之间并没有真正共享数据。单例类将确保您在单个程序中只有该对象的一个​​实例,但两个程序仍将完全相互独立,并且不能以这种方式共享数据。

    即使您只有一个带有“main”的类并且只运行了两次,也会出现这种情况。

    如果您想像这样在程序之间共享数据,您有很多选择,但有些是:

    • 看看您是否真的可以将两个独立的程序合二为一。您真的需要两个程序吗?
    • 使用数据库来存储您的数据,MySQL 和 SQLite 是其中两个简单的选择。
    • 一个程序可以将数据写入文件,而另一个程序可以读取它。
    • 还有许多其他选项可以将数据从一个程序发送到另一个程序,例如套接字(已经存在无数种网络协议,而且您可以自行开发)、特定于平台的东西,例如 Windows 上的命名管道、共享内存等。查看"java ipc" 的 Google 结果(进程间通信——这些是允许两个程序相互通信的通用技术)。

    【讨论】:

    • 我明白你的意思,但我在 cList 中有客户端套接字,我无法将其存储在 db 或文件中,所以你能告诉我一个解决方案来获取所有其他客户端套接字的列表吗任何客户端线程
    • @UmerSufyan 您不能在 Java 程序之间共享套接字本身。你能提供更多关于你想要做什么的细节吗?听起来可能有更好的方法,但如果不了解更多有关您的应用程序的信息,实际上不可能给您任何更可靠的建议。你的两个独立程序实际上做什么?这听起来有点像XY Problem
    • !你对XY问题是对的。我正在制作一个聊天服务器..我想向任何特定的客户端发送一个客户端列表,以便它可以选择任何其他客户端进行聊天。我正在和我的朋友讨论这个问题,现在我只发送 Inetaddress 和端口,现在我将使用 UDP 在客户端之间进行通信。(我之前使用的是 TCP。)这是正确的方法吗?
    【解决方案4】:

    无论何时实现单例,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 中。如果您随后执行 another 程序,您将获得另一个 JVM 和所有相关类的另一个“副本”。因此,您有两个单独的单例——每个程序一个。两者之间不共享类。

    【讨论】:

    • 这是多线程应用程序中的好建议,但这里似乎没有提到线程?
    • @JasonC 是的,我假设他的意思是两个线程,而不是两个程序,因为后者确实使问题变得无稽之谈,哈哈。
    • 也许......虽然初学者误解单例并认为实例是在程序之间共享的可能是合理的,如果他的目标(这似乎是一个秘密......)是共享同时运行的两个程序之间的数据。
    • 可重入锁呢?
    • 对不起!!!我的错。我正在运行两个不同的程序'
    猜你喜欢
    • 2016-03-07
    • 1970-01-01
    • 2016-05-09
    • 1970-01-01
    • 2015-07-27
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    相关资源
    最近更新 更多