?
Solved

Singletons and Garbage collection.

Posted on 2000-02-03
28
Medium Priority
?
1,052 Views
Last Modified: 2013-11-23
I've heard that a singleton in java may
be garbage collected. To get around this you are supposed to put a sleeping thread in it, so that it won't be collected. First of all, is this true? Anyway, I wrote some code to test this, it uses finalize to tell when the garbage collector has run. I can't seem to get the garbage collector to run though. Can anyone tell me how to fix this code, to prove that the singleton is getting garbage collected, or if it isn't getting collected to give me some proof as to why? (It is two classes, the driver and the singleton.)


public class Singleton {
    static Singleton ref = null;
    int count = 0;

    protected Singleton() {}; // Don't use this outside of instance.
   
    public static Singleton instance() {
        if (ref == null) {
            ref = new Singleton();
        }
       
        ref.count++;
        System.out.println("Initializing #" + ref.count);
        return ref;
    }

    public static int getNumber() {
        return ref.count;
    }

    // This is how we tell if the Garbage collector has run
    // finalize() is run when an obj is GB collected.
   protected void finalize() {
        System.out.println("Garbage Collector running.");
    }
   
 
}

public class SingletonDriver {
   static void main (String argv[]) {
        boolean collected = false;
        Singleton sa = Singleton.instance();
        Singleton sb = Singleton.instance();
        String dummy; // to take up space.


        System.out.println("There are " + sa.getNumber() + " objects.");

        sa = null;
        sb = null;

        // Wait for GB collector
        for(int i =0; i < 1000000000; i++) {
            // Just busy wait.
            dummy = new String("Just wasting space" +i);
        }

        System.gc();
      //        System.out.println("collecteed == " + Singleton.collected);
        sa = Singleton.instance();
        System.out.println("There are " + sa.getNumber() + " objects.");
    }
}


Thanks.-



0
Comment
Question by:Artimage
  • 11
  • 9
  • 6
  • +1
28 Comments
 
LVL 16

Expert Comment

by:imladris
ID: 2486876
I'm not sure what your original information was referring to. Certainly not a singleton of the kind you are describing above. Nothing gets garbage collected that still has a valid reference to it. The static in your class will certainly be found as a valid reference.

As some additional comfort I have used this construct:

      private static PosEventQueue obj = new PosEventQueue();

// Don't let anyone instantiate this class
      private PosEventQueue()
      {      scron=true;
            return;
      }

      public static PosEventQueue getPosEventQueue()
      {      return(obj);
      }

This has been running in a production system for over a year without trouble. Note that the class can be instantiated right in an initializer.

0
 
LVL 5

Expert Comment

by:mbormann
ID: 2488855
>>>if it isn't getting collected to give me some proof as to why?

continuing in the same line as imladris ,the JVM will still have a valid reference to the static Singleton class ,why you will ask? Because the Memory Layout on ALL systems is such that there is a Heap, Stack and a special Heap for static objects (& variables ? i am not sure abt the last though),I got this answer from Scott Meyer's excellent book 'More Effective C++'

Also there is a special memory reserved for Strings so your string
"Just wasting space" is cached by the JVM and not allocated again unless you forcibly use a new String("Just wasting space"),if your code is like this I think the gc() will be forced to kick in and run.

new String (new String ("Just wasting space") + i)

what actually happens is that the JVM checks if this particular string is in Memory ,if it is then it reuses it else new String("that string") is called.
try and see a good site on gc
http://www.daimi.au.dk/~beta/Papers/Train/train.html
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2488873
but why
>> // Don't let anyone instantiate this class
>> scron=true;

:)
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
LVL 5

Expert Comment

by:mbormann
ID: 2488945
Now that you point it out, in a static method creating singleton as suggested by GoF the constructor is privatized,but need not have any content.
:(
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2489581
> :(
mbormann, but why are you so sad today ?
0
 
LVL 5

Expert Comment

by:mbormann
ID: 2489710
there's a reason for that ,shall i mail you abt it? If u say so here then will do so else forget it...
0
 
LVL 16

Expert Comment

by:imladris
ID: 2490047
Is there anything more you need clarified before grading the answer?

(scron stands for screen on, and relates to other things going on in the class ;) )
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2490386
mbormann: e-mail me, maybe I can cheer you :)
but its Friday, 19:00, I am going out for a  beer ... talk to you tomorrow friend :)

and have a nice weekend !
0
 

Author Comment

by:Artimage
ID: 2497939
Sorry, it has been a busy few days. I'll try to be more prompt from here on out.

So I found the book, "Patterns in Java volume 1", which states the error that I'm trying to test.

Here is the line. Now I see that it has somthing to do with class loadings, but I'm still not sure how to write code to prove it.

"There is a rather subtle bug than [sic] can occur in implementation of the Singleton pattern. It can cause a Singleton class to create and instatiate more than one insance of itself. The problem occurs in programs that refer to a singleton class only through other classes that are dynamically loaded..."

" ... When a program stops using using classes, the classes that it is finished with may be garbaged collected."


So apperently I need a test that uses the singleton in a dynamically loaded class, then allows that class to be gc'd.

Finally...
Mbormann: I understand that the string is cached, but since I'm adding I to it in the new().. and i is different each time, shouldn't that force a new string to be created?

Artimage.-
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2499055
1. you have one Class object per name per classloader, so you may have more than one class with the same name, but these are different OBJECTS, and usually you won't find them inside the same namespace (in fact this would be a serious BUG).
think of it this way - each classloader has its own classspace, you may have classes with the same name in different namespaces, but EVERY object (usually) works only with classes from its namespace. for example in browser enviroment, you usually have one classloader per applet codebase, so you'll have one classobject / singleton per applet codebase, but every applet will see only ONE singleton.
the statement that you've quoted is quite vague - what does that mean
'...that refer to a singleton class only through other classes that are dynamically loaded... '
in fact in Java all CLASSES are dynamically loaded ...
2.
'... When a program stops using using classes, the classes that it is finished with may be garbaged collected.'
as far as I remember in Java 1.1 (bug or not) the class object won't be garbage collected even when all the class instances are already garbage collected. in Java 2.0 the class objects are garbage collected too.

my 0.05$ :)
0
 
LVL 5

Expert Comment

by:mbormann
ID: 2499207
continuing what heyhey said

a few clarifications
(1)At runtime, a class is uniquely identified both by its fully-qualified class name (package and class name) as well as the class loader that loaded it.

(2)The name spaces created by different class loaders can overlap, have some names in common, and have others quite separate.

>>>>>for example in browser enviroment, you usually have one classloader per applet codebase, so you'll have one classobject / singleton per applet codebase, but every applet will see only ONE singleton.

Generally what happnes is that when asked to load a class, a class loader will first delegate the request to a parent calss loader. In this way, all the class loaders in a VM form a tree, and at the root of this tree is the system class loader (which loads class from the VMs classpath). The classes recognized by a class loader include those classes loaded explicitly by the class loader itself, as well as all those classes recognized by the loaders parent class loader. So, the classes recognized by a particular class loader are a superset of the classes actually loaded by that loader. Its like a inheritance tree.

yes there maybe several applet calss loaders running in browser art same time and they may all have to load class java.applet.Applet. It is essential that all of them return the exact same Class object when asked to load this class. Otherwise, the container (in this particluar case the browser) will not recognize an object generated from one of the loaded applet classes as an object derived from java.applet.Applet. You wouldn't want the container's ( browsers) namespace to be different than any of the individual applet class loader's namespaces, at least not where the class java.applet.Applet is concerned.

So, instead of actually loading the Applet class when asked, an applet class loader must delegate to the system class loader (which loads all of the java.* classes).

Similarly we can argue that your singleton class which maybe loaded over the network will be a 'Singleton' as it's been loaded by your VM's Class Loader

>>>'...that refer to a singleton class only through other classes that are dynamically loaded... '

Probably Mark Grand ,author of 'Patterns in Java' meant to say 'dynamically loaded over the network'

>>>" ... When a program stops using using classes, the classes that it is finished with may be garbaged collected."

Not true of static data ,methods they are kept in a special memory which is I think different from the Heap & stack.So I think I agree with
>>>the class object won't be garbage collected even when all the class instances are already garbage collected.

heyhey,can u give evidence abt this one?
>>>in Java 2.0 the class objects are garbage collected too.
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2499235
heyhey,can u give evidence abt this one?
>>>in Java 2.0 the class objects are garbage collected too.

not at the moment - but if you have time, you can search JavaWorld for 'garbage collection' ... :)

after all Class objects are just normal Java objects - in some specail enviroment - for example if you have some small (embeded ?) device that continuously downloads new application classes and executes them, you really need its JavaVM to garbage collect all the 'old' classes :)

if you don't want your class to be garbage collected, you'll have to keep some global reference to it (or some of its objects).
0
 
LVL 5

Expert Comment

by:mbormann
ID: 2499259
read this http://www.metamech.com/wiki/view/Main/PrimordialClassLoader

About static

A system class is based on CLASSPATH. CLASSPATH cannot be changed during the lifetime of a JVM. System classes are loaded once and only once during the lifetime of a JVM. Because of these things, a static variable is really static for system classes.

Static varibles are initialized once and only once during the lifetime of a JVM.
A non-system class is based on CODEBASE or a custom class loader.
CODEBASE changes from one HTML page to another. A custom class loader can reused many times. Because of these things, a static variable isn't really static for non-system classes.

Static variables are initialized less often than other variables. It may be once
per restart of an applet. It may be once per instance of a custom class loader.

So Artimage ,my answer to your question is that put your Singleton class in the primordial JVM's classpath so it will be loaded only once and yes have a global reference to it for safety sake's as heyhey said.
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2499331
Singleton per classloader is enough for me - classloader namespaces are different universies inside the same JavaVM
0
 

Author Comment

by:Artimage
ID: 2501418
Actually, I'm writing this code to see it not work. ie the singleton's class being gc'd and losing state. But I'm pretty sure I know how I need to do about that now. I need to make a custom class loader that loads my singleton class. Then allow all references to be garbage collected. Then get a new instance. This should show me that it is possible for a Singleton to lose state.

I still don't understand one thing though, why does the finalize in the above code never print anything?

Thanks.-
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2501506
you don't keep references to your Strings, so they won't fill the memory quickly enough ...

about the Singleton stuff - as I already said - Singleton per Classloader is single enough - after all your next step is singleton per VM which is not much better ... classloader space is THE UNIVERSE - not the Java VM space (which is system classloader space)

all your current objects live in the same namespace. if you can access two different version of the 'same' class (loaded from two different classloaders) - you already have a problem to FIX :)

regarding class GC, my JavaVM (-noclassgc option) says that it CAN garbage collect classes, but I doubt that this is true :)

usage: java [-options] class

where options include:
    -help             print out this message
    -version          print out the build version
    -v -verbose       turn on verbose mode
    -debug            enable remote JAVA debugging
    -noasyncgc        don't allow asynchronous garbage collection
    -verbosegc        print a message when garbage collection occurs
    -noclassgc        disable class garbage collection

best regards
  heyhey
0
 
LVL 5

Expert Comment

by:mbormann
ID: 2503324
Perhaps this helps?

/*****************************************************************************
 * Copyright (c) 1999, KL GROUP INC.  All Rights Reserved.
 * http://www.klgroup.com
 *
 *****************************************************************************/


import java.lang.reflect.*;
import java.util.*;

/*************************************************************
 *
 * A utility class for identifying loitering objects.  Objects
 * are tracked by calling <code>ObjectTracker.add()</code> when instantiated,
 * and calling </code>ObjectTracker.remove()</code> when finalized.  Only
 * classes that implement </code>ObjectTracker.Tracked</code> can be tracked.
 * As instances are created and destroyed, they are reported
 * to the stdout.  Summaries by class can also be reported on demand.
 *
 * <P>
 * In order to enable this functionality, add <code>-DObjectTracker</code>
 * when running your program.  This will track all classes that implement
 * <code>ObjectTracker.Tracked</code> and call add/remove as indicated in the
 * previous paragraph.
 *
 * <P>
 * For a finer degree of control, specify a list of filters
 * when setting the <code>ObjectTracker</code> property.  For instance,
 * <code>-DObjectTracker=+MySpecialClass,-ClassFoo</code> will only report
 * on instances of classes whose name contains <code>MySpecialClass</code>
 * but not <code>ClassFoo</code>.  Hence <code>MySpecialClassBar</code>
 * will be tracked, while <code>MySpecialClassFoo</code> will not be.
 * See <A HREF="ObjectTracker.html#start()"> start()</A> for more details.
 *
 * <P>
 * <B>Limitations</B>
 *
 * <P>
 * Since you must add instrumentation to all the classes you want to
 * track, this is not nearly as useful as a Memory Profiler/Debugger
 * like <I>JProbe Profiler</I>.  Also, since it cannot tell you which references
 * are causing the object to loiter, it doesn't help you remove clean
 * up the loiterers.  If you want to solve the problem, you really need
 * to use a Memory Profiler/Debugger like <I>JProbe Profiler</I>.  The only
 * thing that ObjectTracker can help with is testing whether an instance
 * of a known class goes away.
 * <P>
 * <B>Implementation Notes</B>
 *
 * <P>
 * The current implementation assumes that every object has a unique
 * hashcode.  This is a false assumption in general, but does work
 * in JavaSoft's Win32 VM for JDK1.1.
 *
 * <P>
 * This implementation will definitely not work in JavaSoft's
 * implementation of the Java 2 VM, including the HotSpot VM.
 *
 *************************************************************
 */
public class ObjectTracker {

// Property ObjectTracker turns this on when set
private final static boolean ENABLED =
      System.getProperty("ObjectTracker") != null;

// Classes are hashed by name into this table.
private static Hashtable classReg;
private static Vector       patterns;

/** Record info about an object.  Class and ordinal number are stored. */
private static class ObjectEntry {
      int            ordinal;            // distinguishes between mult. instances
      String      clazz;                  // classname
      String  name;                  // name (may be null)

      public ObjectEntry(int ordinal, String clazz, String name) {
            this.ordinal = ordinal;
            this.clazz   = clazz;
            this.name    = name;
      }

      public String toString() {
            return clazz + ":#" + ordinal + " ("+name+")";
      }
} // ObjectEntry

/**
 * Records info about a class.  Within each class, a table of objects
 * is maintained, along with the next ordinal to use to stamp the
 * next object of this class.
 */
private static class ClassEntry {
      String            clazz;                  // class name
      Hashtable      objects;            // list of ObjectEntry
      int                  ordinal;            // last instance of this class created

      public ClassEntry(String clazz) {
            this.clazz = clazz;
            objects    = new Hashtable();
            ordinal    = 1;
      }

      public String toString() {
            return clazz;
      }

      /**
       * Get the name of the object by invoking getName().
       * Uses reflection to find the method.
       */
      private String getName(Object o) {
            String name = null;
            try {
                  Class cl = o.getClass();
                  Method m = cl.getMethod("getName", null);
                  name = (m.invoke(o, null)).toString();
            }
            catch (Exception e) { }

            return name;
      }

      public void addObject(Object obj) {
            // Store this object in the object table
            Integer id = new Integer(System.identityHashCode(obj));
            ObjectEntry entry = new ObjectEntry(ordinal, clazz, getName(obj));
            objects.put(id, entry);
            ordinal++;

            System.out.println("    added: " +entry);
      }

      public void removeObject(Object obj) {
            // Removes this object from the object table
            Integer id = new Integer(System.identityHashCode(obj));
            ObjectEntry entry = (ObjectEntry) objects.get(id);
            objects.remove(id);

            System.out.println("    removed: " +entry);
      }

      /** Dump out a list of all object in this table */
      public void listObjects() {
            if (objects.size() == 0)  {
                  // skip empty tables
                  return;
            }

            System.out.println("For class: " + clazz);
            Enumeration objs = objects.elements();
            while (objs.hasMoreElements()) {
                  ObjectEntry entry = (ObjectEntry) objs.nextElement();
                  System.out.println("    " +entry);
            }
      }
} // ClassEntry

/** No constructor */
private ObjectTracker() {}

/**
 * Determine is this class name should be tracked.
 * @return true if this class should be tracked.
 * @see start
 */
private static boolean isIncluded(String clazz) {
      int i=0, size = patterns.size();

      if (size == 0) {
            // always match if list is empty
            return true;
      }

      boolean flag = false;
      for (; i<size; i++) {
            String pat = (String) patterns.elementAt(i);
            String op = pat.substring(0, 1);            // + or -
            String name = pat.substring(1);
            if (name.equals("all")) {
                  if (op.equals("+"))
                        flag = true;            // match all, unless told otherwise
                  else if (op.equals("-"))
                        flag = false;            // match nothing, unless told otherwise
            }
            else if (clazz.indexOf(name) != -1) {
                  // match if any of the filter names is a substring of
                  // the class name
                  if (op.equals("+"))
                        return true;
                  else if (op.equals("-"))
                        return false;
            }
      }

      return flag;
}

/**
 * Must be called before any objects can be tracked.  Turns on object tracking
 * if property <code>ObjectTracker</code> is set.  In addition, the list
 * of patterns assigned to this property is stored for future pattern
 * matching by <code>isIncluded()</code>.  This list of patterns must
 * be supplied as a comma-separated list, each one preceded by a
 * <code>+</code> or <code>-</code>, which indicates whether or not
 * the pattern should cause matching classes to be tracked or not.  
 * If the property <code>ObjectTracker</code> has no values, it is
 * equivalent to <code>+all</code>.
 */
public static void start() {
      if (ENABLED) {
            classReg = new Hashtable();
            patterns = new Vector();

            String targets = System.getProperty("ObjectTracker");
            StringTokenizer parser = new StringTokenizer(targets, ",");
            while (parser.hasMoreTokens()) {
                  String token = parser.nextToken();
                  patterns.addElement(token);
            }
      }
}

/**
 * Add object to the tracked list.  Will only be added if the
 * object's class has not been filtered out.
 *
 * @param obj object to be added to tracking list
 */
public static void add(Tracked obj) {
      if (ENABLED) {
            String clazz = obj.getClass().getName();
            if (isIncluded(clazz)) {
                  ClassEntry entry = (ClassEntry) classReg.get(clazz);
                  if (entry == null) {
                        // first one for this class
                        entry = new ClassEntry(clazz);
                        classReg.put(clazz, entry);
                  }
                  entry.addObject(obj);
            }
      }
}

/**
 * Removes object from tracked list.  This method should be called
 * from the finalizer.
 *
 * @param obj object to be removed from tracking list
 */
public static void remove(Tracked obj) {
      if (ENABLED) {
            String clazz = obj.getClass().getName();
            if (isIncluded(clazz)) {
                  ClassEntry entry = (ClassEntry) classReg.get(clazz);
                  entry.removeObject(obj);
            }
      }
}

/**
 * Print tracked objects, summarized by class.  Also prints a
 * summary of free/total memory.
 */
public static void dump() {
      if (ENABLED) {
            Enumeration e = classReg.elements();
            while (e.hasMoreElements()) {
                  ClassEntry entry = (ClassEntry) e.nextElement();
                  entry.listObjects();
            }

            System.out.println("==================================");
            System.out.println("Total Memory: " +
                  Runtime.getRuntime().totalMemory());
            System.out.println("Free  Memory: " +
                  Runtime.getRuntime().freeMemory());
            System.out.println("==================================");
            System.out.println("");
      }
}

/**
 * All classes that want to use this service must implement this
 * interface.  This forces this class to implement Object's finalize
 * method, which should call <code>ObjectTracker.remove()</code>.
 */
public interface Tracked {
      /**
       * All classes that use ObjectTracker must implement a finalizer.
       */
      void finalize();
}

}


/*****************************************************************************
 * Copyright (c) 1999, KL GROUP INC.  All Rights Reserved.
 * http://www.klgroup.com
 *
 *****************************************************************************/

public class tester implements ObjectTracker.Tracked {
      private int[] junk = new int[5000];

      public static void main(String args[]) {
            ObjectTracker.start();

            for (int i=0; i<1000; i++) {
                  tester t = new tester();
                  t.doNothing();
                  if (i%100 == 0) {
                        System.gc();
                  }
            }
            ObjectTracker.dump();
      }

      public tester() {
            ObjectTracker.add(this);
      }

      public void finalize() {
            ObjectTracker.remove(this);
      }

      public void doNothing() {
      }
}
0
 

Author Comment

by:Artimage
ID: 2504902
heyhey: "you don't keep references to your Strings, so they won't fill the memory quickly enough ... "

How does that work, I would assume that new would create the string, and then to get rid of it the garbage collector would have to be called. How is it that my not keeping the reference outside the loop scope is making it not fill up memory? TIA.
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2506862
GC will be called, but it will probably release the String objects (which are much more and much simpler objects :) it is not 'obligated' to release all the objects.

and one thing that I didn't notice - you still have reference to this Object from a static variable, so it won't be garbage collected at all. (GC of classes is tricky :)

and onr thing more - if Java VM is your OS, that different classloader spaces are your processes. singleton per process is what you'll get when you work with Windows and app written in C++ too.
0
 

Author Comment

by:Artimage
ID: 2508777
Are you sure that the static reference will prevent class garbage collection? The book doesn't seem to think so. They have a static reference to the class, but they still create a sleeping thread to guard against GC.

Maybe you have a good pointer where I can read about the rules for GC in the java VM? Tia.

Artimage.-
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2510959
>> Are you sure that the static reference will prevent class garbage collection?

sounds quite sensible to me :)
can you post the example code from the book ?
0
 

Author Comment

by:Artimage
ID: 2512497

Sure. This is the code he uses to make sure the singleton is not GC'd, and the class below it is his Singleton example.

:)


/**
 * This class has methods to ensure that an object is never garbage
 * collected.
 */
public class ObjectPreserver implements Runnable {
    // This keeps this class and everything it references from being
    // garbage collected
    private static ObjectPreserver lifeLine = new ObjectPreserver();

    // Since this class won't be garbage collected, neither will this
    // HashSet or the object that it references.
    private static HashSet protectedSet = new HashSet();

    /**
     * Constructor.
     */
    private ObjectPreserver() {
        new Thread(this).start();
    } // constructor()

    public void run() {
        try {
            wait();
        } catch (InterruptedException e) {
        } // try
    } // run()

    /**
     * Garbage collection of objects passed to this method will be
     * prevented until they are passed to the unpreserveObject method.
     */
    public static void preserveObject(Object o) {
        protectedSet.add(o);
    } // preserveObject()

    /**
     * Objects passed to this method lose the protection that the
     * preserveObject method gave them from garbage collection.
     */
    public static void unpreserveObject(Object o) {
        protectedSet.remove(o);
    } // unpreserveObject(Object)
} // class ObjectPreserver


import java.applet.AudioClip;

/**
 * This class can be used to avoid playing two audio clips at the same
 * time.  The class has only one instance that can be accessed through
 * its getInstance method.  When you play audio clips through that
 * object, it stops the last audio clip it was playing before
 * it starts the newly requested one.  If all audio clips are played
 * through the AudioClipManager object then there will never be more
 * than one audio clip playing at the same time.
 */
public class AudioClipManager implements AudioClip{
    private static AudioClipManager myInstance
      = new AudioClipManager();
    private AudioClip prevClip; // previously requested audio clip

    /**
     * This private constructor is defined so the compiler won't
     * generate a default public constructor.
     */
    private AudioClipManager() { }

    /**
     * Return a reference to the only instance of this class.
     */
    public static AudioClipManager getInstance() {
        return myInstance;
    } // getInstance()

    /**
     * Start playing this audio clip. Each time this method is called,
     * the clip is restarted from the beginning.
     */
    public void play() {
        if (prevClip != null)
          prevClip.play();
    } // play()

    /**
     * Stop the previously requested audio clip and play the given audio
     * clip.
     * @param clip the new audio clip to play.
     */
    public void play(AudioClip clip) {
        if (prevClip != null)
          prevClip.stop();
        prevClip = clip;
        clip.play();
    } // play(AudioClip)

    /**
     * Starts playing this audio clip in a loop.
     */
    public void loop() {
        if (prevClip != null)
          prevClip.loop();
    } // loop()

    /**
     * Stop the previously requested audio clip and play the given audio
     * clip in a loop.
     * @param clip the new audio clip to play.
     */
    public void loop(AudioClip clip) {
        if (prevClip != null)
          prevClip.stop();
        prevClip = clip;
        clip.loop();
    } // play(AudioClip)

    /**
     * Stops playing this audio clip.
     */
    public void stop() {
        if (prevClip != null)
          prevClip.stop();
    } // stop()
} // class AudioClipManager
0
 
LVL 16

Accepted Solution

by:
heyhey_ earned 300 total points
ID: 2514262
have you tried this code ? it seems to me that you'll get java.lang.IllegalMonitorStateException the first time you try to 'ensure that an object is never garbage collected.' :)
(not sure though)

this class may keep some objects from from being garbage collected, but I still don't see why static references won't work :)
0
 

Author Comment

by:Artimage
ID: 2520608
No I haven't tried the code, I just read the example from the book. :(  I don't see why your reference won't work either, which is why I posted.... I guess it may be one of those things where I'll end up emailing the author. :)

Art.-

PS. Since your the last man standing I figure you deserver the points.
0
 
LVL 5

Expert Comment

by:mbormann
ID: 2521609
>>>I guess it may be one of those things where I'll end up emailing the author. :)

Do post it here too and let us know ur results.

>>>PS. Since your the last man standing I figure you deserver the points.

:)
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 2522283
Thanks :)
0
 
LVL 5

Expert Comment

by:mbormann
ID: 2536760
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: narshlob
If you've ever programmed in Ruby and have come across either a proc or a lambda, you might have been wondering what the difference is between the two and when you would use one over the other. This article will try to explain the difference between…
Java functions are among the best things for programmers to work with as Java sites can be very easy to read and prepare. Java especially simplifies many processes in the coding industry as it helps integrate many forms of technology and different d…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Suggested Courses
Course of the Month4 days, 9 hours left to enroll

601 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question