3

I'm trying to make Clients class singleton, but it is not working. Here is my class:

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;
    }
}

I am getting this instance in two different classes(both have their own main function). After getting its instance in one class, I get it in another class, but both tiare still executing.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Umer Sufyan
  • 156
  • 1
  • 8
  • 3
    Are you accessing from multiple threads? – Sam Mar 28 '14 at 21:41
  • 1
    What are you trying to achieve? – dimoniy Mar 28 '14 at 21:42
  • Also, you mentioned both classes have their own main method. Does this mean you are running two separate programs that access the singleton? If so, singletons don't extend beyond a specific process boundary – Sam Mar 28 '14 at 21:42
  • I'm confused. You're doing this in two classes, and _both have their own main function_; does that mean you're compiling and running two different programs? – ajb Mar 28 '14 at 21:43
  • Possible duplicate of http://stackoverflow.com/questions/11165852/java-singleton-and-synchronization – Jason C Mar 28 '14 at 21:56
  • Or duplicate of http://stackoverflow.com/questions/21950823/java-access-singleton-class-instances-from-two-main-class?rq=1 if he actually means "programs" and not "threads" (see contradictory comments on Jeff Gohlke's answer). – Jason C Mar 28 '14 at 21:58

4 Answers4

5

Whenever implementing a singleton, the getInstance() method should be thread-safe.

e.g.,

public static synchronized Clients getInstance()

... or ...

private static final Object INSTANCE_LOCK = new Object();

public static Clients getInstance() {
    synchronized(INSTANCE_LOCK) {
        if(instance == null) instance = new Clients();
    }
    return instance;
}

Of course, if you're in fact executing this bit of code from two different programs rather than two different threads, you'll have two instances. I'm assuming the former, because the latter makes your question nonsensical.

I suppose I should explain why that's nonsensical.

When you execute a Java program with a main(String[] args) method, all of your classes are loaded into the JVM. If you then execute another program, you get another JVM and another "copy" of all the associated classes. Thus, you have two separate singletons -- one for each program. Classes aren't shared between the two.

asteri
  • 11,402
  • 13
  • 60
  • 84
  • This is good advice in a multithreaded application, but it did not seem like threads were mentioned here? – Jason C Mar 28 '14 at 21:45
  • 1
    @JasonC Yeah, I'm assuming he means two threads, not two programs, because the latter literally makes the question nonsense, haha. – asteri Mar 28 '14 at 21:46
  • 1
    Maybe... although it could be reasonable for a beginner to misunderstand singletons and think that the instance is shared between programs, if his goal (which seems to be a secret...) is to share the data between two running programs at the same time. – Jason C Mar 28 '14 at 21:47
  • What about reentrant locks? – Mr. Polywhirl Mar 28 '14 at 21:48
  • @Mr.Polywhirl Certainly you could use them instead, but these two methods are the most straightforward for a beginner. – asteri Mar 28 '14 at 21:49
  • I heard that synchronized is very resource heavy and frowned upon. Use sparingly. – Mr. Polywhirl Mar 28 '14 at 21:51
  • Well, good thing the OP cleared that up, there you go! – Jason C Mar 28 '14 at 21:55
  • Thanks,, i was running two different programs,, but now i got your point.. – Umer Sufyan Mar 28 '14 at 21:56
  • @UmerSufyan Wait, you just said in your question comments that you were running two different threads. Are you running two different programs? Or two different threads in the same program? Threads != Programs. – Jason C Mar 28 '14 at 21:57
  • 1
    sorry!!! my bad. i am running two different programms' – Umer Sufyan Mar 28 '14 at 22:02
  • Is there any reason to lock if `instance != null`? Once the instance has been created, `instance` will never be changed back to null, so I think if this is checked first, before the lock, most of the overhead for `synchronized` will go away. Inside the `synchronized`, you'd have to recheck because `instance` could become non-null while waiting for the lock. – ajb Mar 28 '14 at 22:07
  • Specifically: `if (instance == null) { synchronized(INSTANCE_LOCK) { if (instance == null) instance = new Clients(); } }` – ajb Mar 28 '14 at 22:10
  • Looks like the link in @chillworld's answer says basically the same thing. – ajb Mar 29 '14 at 00:14
  • @ajb If you do it that way, then there's still the potential for the instance to be created twice. If the threads enter the `getInstance()` method and both evaluate `instance == null` as `true`, then one will instantiate the object while the other waits on the lock. Then, it will instantiate it again. – asteri Mar 29 '14 at 00:16
  • @JeffGohlke It will? If one instantiates the object while the other waits, then when the second one gets into the lock, the second `instance==null` test will be false, right, since the first thread has set it? Assuming `instance` is declared `volatile` so that the compiler doesn't optimize away reading the member again. – ajb Mar 29 '14 at 00:26
  • @ajb Ah, correct. I was just skimming your comment before dinner and didn't notice your second `if` statement. Makes sense, and it's probably a performance gain. Would have to benchmark it to be sure. – asteri Mar 29 '14 at 00:29
  • @ajb I finally did a performance test on this. You were right. Your version is an order of magnitude faster than having the `synchronized` block getting entered each time. – asteri Apr 04 '14 at 13:54
5

You mentioned that both classes "have their own main", so I am assuming you have two separate programs.

Long story short, data isn't really shared between two programs. A singleton class will ensure you only have one instance of that object within a single program, but two programs will still be completely independent of each other and cannot share data this way.

This would be the case even if you only had one class with a "main" and just ran it twice.

If you want to share data between programs like this, you have many, many options, but some are:

  • See if you can actually combine your two separate programs into one. Do you really need two programs?
  • Use a database to store your data, MySQL and SQLite are two easy options, among many.
  • One program can write data to a file, and the other program can read it.
  • There are many other options to send data from one program to another, such as sockets (there are a zillion network protocols that already exist, plus you could roll your own), platform-specific things like named pipes on Windows, shared memory, etc. Check out the Google results for "java ipc" (Inter-Process Communication -- these are general techniques for allowing two programs to communicate with eachother).
Jason C
  • 38,729
  • 14
  • 126
  • 182
  • I got your point but i have sockets of clients in cList which i cant store in db or in a file,,, so can you tell me a solution to get the list of all other client sockets in any client thread – Umer Sufyan Mar 28 '14 at 22:01
  • @UmerSufyan You can't share sockets themselves between programs in Java. Can you provide a little more detail about what you are trying to do? It sounds like there may be a better way, but it isn't really possible to give you any more solid advice without knowing more about your application. What do your two separate programs actually *do*? This is starting to sound a little bit like an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Jason C Mar 28 '14 at 22:23
  • ! you are right about XY problem. I am making a chat server.. i want to sent a list of clients to any specific client so that it can choose any other client to chat. I was discussing it with my friend and now i am sending just Inetaddress and port and now i will use UDP to do communication between clients.(I was using TCP before.) Is this the right approach? – Umer Sufyan Mar 29 '14 at 09:15
2

You could use a synchronized block above as Jeff Gohlke has stated, but you may also want to look into using locks.

The best thing about locks are that synchronized keyword doesn’t provide fairness whereas we can set fairness to true while creating ReentrantLock object so that longest waiting thread gets the lock first.

// 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();
    }    
}
Community
  • 1
  • 1
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • 3
    I've never seen anybody use `` for user links before. That's kind of cool looking. – Jason C Mar 28 '14 at 22:24
  • 1
    Somehow I found myself here 7 years later, I looked at the answer, thought "huh, kbd for user links, interesting, and kind of cool looking", and was then mildly amused when I discovered I had already commented on it. I feel so.... consistent, haha. – Jason C May 15 '21 at 19:36
  • 1
    @JasonC Nice… – Mr. Polywhirl May 15 '21 at 22:21
0

You can get rid of a lot of your problems by just doing

private static Clients instance = new Clients().

No need to worry about the locking idiom in get instance. There's not point in doing this sort of lazy instantiation unless the class that you are building is expensive to build.

Having said that, I'm not sure I like the getter and setter for the cList either. I'd prefer these to be instance methods on the class you are making a singleton, so you'd do ( for example )

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

And, if this is a multithreaded environment then you'd have to be aware that the setter may affect other threads that already have a refernce to the singleton object.

DaveH
  • 7,187
  • 5
  • 32
  • 53