如何使我的代码线程安全?

时间:2015-01-22 09:50:07

标签: java multithreading thread-safety

给定一个Factory类,使用静态方法为SomeModel类创建实例,它将在多线程环境中运行。这个Factory有三种方法:

  1. 启动
  2. 停止
  3. createSomeModel
  4. state字段位于:

    1. shutted
    2. 起始
    3. starting_failed
    4. 开始
    5. shutting_failed
    6. 这是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==startedstart方法只能在state==shutted || state == shutting_failed调用时调用,而stop方法只能调用在state==started|| state == starting_failed时调用。

      我知道这与线程同步问题有关,但我对我的线程知识没有信心。请帮帮我。

3 个答案:

答案 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 {}
}