给定一个Factory
类,使用静态方法为SomeModel
类创建实例,它将在多线程环境中运行。这个Factory
有三种方法:
和state
字段位于:
这是Factory
类的当前设计:
public class Factory {
enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed
}
State state;
public static void start(){
// can only be invoked when state=shutted
}
public static void stop(){
// can only be invoked when state=started
}
public static void restart(){
stop();
start();
}
public static SomeModel create(){
// can only be invoked when state=started
}
}
我的要求是:create
方法只能在state==started
和start
方法只能在state==shutted || state == shutting_failed
调用时调用,而stop
方法只能调用在state==started|| state == starting_failed
时调用。
我知道这与线程同步问题有关,但我对我的线程知识没有信心。请帮帮我。
答案 0 :(得分:0)
此方法不会同步创建方法,因此这不会成为瓶颈。而当你停止时,不要让新的执行创造。 双重检查“if state == started”是必要的,以避免竞争条件。
可能有更好的解决方案,而不是使用Thread.sleep等待所有创建模型完成,但我不明白如何轻松做到。
希望这可以帮到你。
enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed
}
private Factory() {
// singleton: no more than 1 instances allowed
}
public static Factory getInstance() {
return instance;
}
private static final Factory instance = new Factory();
private final AtomicInteger threadsCreatingModel = new AtomicInteger();
private volatile State state;
public synchronized void start(){
if(state != State.shutted) {
throw new RuntimeException("Can only be invoked when state=shutted");
}
state = State.starting;
// TODO: task
}
public synchronized void stop() throws InterruptedException {
if(state != State.started) {
throw new RuntimeException("Can only be invoked when state=started");
}
state = State.shutting;
// wait all threads that are creating SomeModel
while (threadsCreatingModel.intValue() > 0) {
Thread.sleep(500);
}
// TODO: task
}
public SomeModel create(){
if(state == State.started) {
threadsCreatingModel.incrementAndGet();
if(state == State.started) {
// TODO: task
}
threadsCreatingModel.decrementAndGet();
}
}
答案 1 :(得分:0)
我建议你根本不要使用静态方法。
更确切地说,创建Factory
类的对象,并让所有方法都为synchronized
。
public enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed;
}
public class Factory {
private State state;
public synchronized void start(){
if(state != State.shutted) {
throw new RuntimeException("Can only be invoked when state=shutted");
}
// do task
}
public synchronized void stop(){
if(state != State.started) {
throw new RuntimeException("Can only be invoked when state=started");
}
// do task
}
public synchronized void restart(){
stop();
start();
}
}
希望这有帮助。
答案 2 :(得分:0)
无需同步。使用volatile或AtomicReference for State。 我给出了使用volatile的示例。最好与原始类型一起使用,因此必须为不同的状态添加int值。虽然你可以使用枚举的序数但这种方式有点清楚。否则,您可以使用AtomicReference。
public class Factory {
private static volatile int factoryState;
public synchronized void updateFactoryState(State newState, State ... expectedStates){
for (State state : expectedStates)
if(factoryState == State.shutted.getStateVal()){
factoryState = newState.getStateVal();
}
}
public void start(){
try{
updateFactoryState(State.starting, State.shutted, State.shutting_failed);
System.out.println("steps to start the factory");
//someExpensiveStartupMethod();
}catch (Exception e){
updateFactoryState(State.starting_failed, State.starting);
}
updateFactoryState(State.started, State.starting);
}
public void stop(){
try{
updateFactoryState(State.shutting, State.started, State.starting_failed);
System.out.println("steps to stop the factory");
//someExpensiveStopFactoryMethod();
}catch (Exception e){
updateFactoryState(State.shutting_failed, State.shutting);
}
updateFactoryState(State.shutted, State.shutting);
}
public void restart(){
stop();
start();
}
public static SomeModel create(){
if(factoryState == State.started.getStateVal()) {
System.out.println("Create Model");
} else{
throw new RuntimeException("Can not create Model.Factory not in started state.");
}
return null;
}
enum State{
shutted(0), starting(1), starting_failed(2), started(3), shutting(4), shutting_failed(5);
private final int stateVal;
State(int i) {
stateVal = i;
}
public int getStateVal() {
return stateVal;
}
}
class SomeModel {}
}