Reputation: 765
I have a singleton Service implementaion class using Enum in my java web applcaition. It start once at application start and shutdown when applcaition was undeployed. and It provide some service method to client:
public enum SingletonService{
INSTANCE;
private boolean isStarted;
public synchronized void start(){
if(!isStarted){
// do initialization stuff
isStarted = true;
}
}
public void stop(){
checkStarted();
// do stop jobs
isStarted = false;
}
private synchronized void checkStarted(){
if(!isStarted)
throw new RuntimeException("SingletonService is not ready");
}
public void service(){
checkStarted();
// do service job
}
}
Threading is a bit hard for me, I am worrying that I missed tricky bugs in my code. Is that necessary to make start
and checkStarted
synchronized? Please tell me any bad thing in such code. I also want to know If there is a common pattern for doing such thing in java?
Upvotes: 2
Views: 118
Reputation: 1535
Code is thread-safe when it is guaranteed to behave as expected when used from multiple threads at once. Therefore it's hard to judge whether this particular code is thread-safe not knowing what it's expected behavior is. But I'll try and guess. I guess, that you expected, among others, that if checkStarted()
called from INSTANCE.service()
does not throw an exception, than the service()
method may proceed safe in an assumption that your singleton will not get stopped before service()
completes it's execution. With this assumption the answer is: your code is not thread-safe, you should, for example, add synchronize
to both stop
and service
methods. You can then get rid of synchronized
on checkStarted
, as mentioned by @Guarava Agarwal's answer.
To see this, consider two threads. Thread A calls INSTANCE.start()
followed by INSTANCE.stop()
and thread B calls INSTANCE.service()
. The following sequence of executions is not prohibited by your current synchronization:
INSTANCE.start()
. isStarted
is set to true
.INSTANCE.stop()
and executes INSTANCE.checkStarted()
(no exception thrown).INSTANCE.service()
and executes INSTANCE.checkStarted()
(again, no exception thrown).INSTANCE.stop()
, setting isStarted
to false
.Upvotes: 2
Reputation: 974
Two comments with reasons:
stop is public, it's changing state of service. it should be declared synchronized instead. Two threads accessing stop/start at the same time should access isStarted in synchronized way.
public enum SingletonService{
INSTANCE;
private boolean isStarted;
public synchronized void start(){
if(!isStarted){
// do initialization stuff
isStarted = true;
}
}
public synchronized void stop(){
checkStarted();
// do stop jobs
isStarted = false;
}
private void checkStarted(){
if(!isStarted)
throw new RuntimeException("SingletonService is not ready");
}
public void service(){
checkStarted();
// do service job
}
}
Upvotes: 1