I have a program which uses singleton pattern. I need to use threads with it taking in mind the output should be the same before and after using threads mechanize. I mean to avoid the case of "broken pattern" where the thread ignore the singleton and create more the one object. But, I failed .I tried to use the “synchronized”, but nothing change. the same wrong result.
My main with the Runnable
public class Main implements Runnable {
Ma开发者_如何学Cin(){}
public void run ()
{
Counter[] counters = new Counter[5];
for(int i = 0; i < counters.length; i++)
{
counters[i] = Counter.getCounter();
}
for(int i = 0; i < counters.length; i++)
{
counters[i].increment();
System.out.println("counter[" + i + "] = " + counters[i]);
}
for(int i = 0; i < 5; i++) {
counters[i].decrement();
System.out.println("counter[" + i + "] = " + counters[i]);
}}
public static void main(String[] args)
{
Main m1=new Main();
Main m2=new Main();
Main m3=new Main();
new Thread(m1).start();
new Thread(m2).start();
new Thread(m3).start();
}
}
The other class which applies the singleton pattern
public class Counter {
private static Counter myInstance = null;
public static Counter getCounter()
{
if(myInstance == null)
{
synchronized (Counter.class) {
if(myInstance == null)
{
myInstance = new Counter();
}
}
}
return(myInstance);
}
private int myCounter;
private Counter() {
myCounter = 0;
}
public void increment() {
myCounter++;
}
public void decrement() {
myCounter--;
}
public String toString() {
return(Integer.toString(myCounter));
}
}
Don't use the double-checked singleton pattern, it's not the modern way to do it, whether it's broken or not.
Singletons in Java should be implemented using either an inner class or an enum (see Effective Java Item 3: Enforce the singleton property with a private constructor or an enum type):
a) Inner Class Singleton Pattern:
public class MySingleton{
private MySingleton(){}
private static class InstanceHolder{
private static final MySingleton INSTANCE = new MySingleton();
}
public static MySingleton getInstance(){
return InstanceHolder.INSTANCE;
}
}
b) Enum Singleton Pattern
public enum MySingleton{
INSTANCE;
public static MySingleton getInstance(){
return INSTANCE;
}
}
Double checked locking used to be broken in Java. I don't know if the new memory model fixes it.
Besides the question "Do I really need a Singleton?", what on earth is lazy instantiation of the Singleton buying you?
Nothing.
It might be justifiable if your Singleton was very expensive to instantiate and there was a possibility that you might not use it. But neither one is the case here.
So if you must, write it like this:
public class Counter
{
// Edited at the recommendation of Sean and "Effective Java"; see below
private static class InstanceHolder
{
private static final Counter INSTANCE = new Counter();
}
private Counter() {}
public static Counter getInstance() { return InstanceHolder.INSTANCE; }
// The rest of the implementation follows.
}
Not entirely sure what you are trying to achieve but there's a few things wrong.
increment/decrement
are not thread-safe. ++ and -- are NOT atomic operations. You either need to synchronize both these methods or useAtomicInteger
with its atomic increment/decrement methodsYou are reading the value of the counter separate from the modification of it so another thread may have changed to value in between updating and reading it for the
println
. I would suggest using AtomicInteger and returning the new value from increment/decrement if you need to display itLooking at the above two points you can probably replace Counter with a static AtomicInteger instance
The double-checked locking in
getCounter
is possibly broken. I'm not sure what the behaviour of statics is outside of a synchronized wrt to visibility. To be safe I would remove the initial null-checkYour required output is not going to come out of this code. Each thread, of which there are 3, is taking the same instance of Counter, 5 times and printing twice each. By my count that is 30 output statements.
The order of those outputs can never be predicted as you have threads competing to increment/decrement the (single) counter value so it may bump up and down in a random fashion. Plus the printing of the number value could appear out of order as the threads compete for that too
It is bad practice to synchronize on a class, especially a public class as other code can sychronize on it and interfere with your locking. Best way is to have a
private static final Object lock = new Object();
and sync on thatYou don't need to put () around return statements
Hope some of that helps! Multi-threaded code is a difficult/dangerous business so please do tread carefully! Perhaps if you asked a question stating your objective someone could help you out with some tips and/or a model answer.
You have to synchronize the whole method. Here's why your code is wrong
It makes most sense to initialize singleton in the static block and not check anything, unless you have thousands of typically unused singleton classes it will not affect the performance.
You missed volatile
in
private static volatile Counter myInstance;
This should fix it, but do not do it. Use the Holder Pattern or eager initialization as shown. Or better, use Dependency Injection instead of the Singleton antipattern.
精彩评论