有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

  1. 开始
  2. 住手
  3. createSomeModel

state字段,位于:

  1. 关闭
  2. 开始
  3. 启动_失败
  4. 开始
  5. 关闭
  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==started时调用,start方法只能在state==shutted || state == shutting_failed时调用,stop方法只能在state==started|| state == starting_failed时调用

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


共 (3) 个答案

  1. # 1 楼答案

    此方法不会同步create方法,因此这不会成为瓶颈。当你停下来的时候,不要让新的创造物被执行。 双重检查“if state==started”是避免竞争条件所必需的

    可能有比使用线程更好的解决方案。睡眠等待所有创建模型完成,但我不知道如何轻松完成

    希望这能对你有所帮助

    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();
        }
    }
    
  2. # 2 楼答案

    不需要同步。对状态使用volatile或AtomicReference。 我给出了使用volatile的示例。最好与基元类型一起使用,因此必须为不同的状态添加int值。虽然你可以使用枚举的序数,但这样就有点清楚了。否则可以使用原子引用

    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 {}
    }
    
  3. # 3 楼答案

    我建议您根本不要使用静态方法

    相反,创建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();
        }
    }
    

    希望这有帮助