Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使我的代码线程安全?_Java_Multithreading_Thread Safety - Fatal编程技术网

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

Java 如何使我的代码线程安全?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,给定一个带有静态方法的Factory类为SomeModel类创建实例,它将在多线程环境中运行。此工厂有三种方法: 开始 停止 createSomeModel 以及状态字段,该字段位于: 关闭 开始 启动\u失败 开始 关闭 关闭\u失败 以下是工厂类的当前设计: public class Factory { enum State{ shutted, starting, starting_failed, started, shutting, shutting_failed

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

  • 开始
  • 停止
  • createSomeModel
  • 以及
    状态
    字段,该字段位于:

  • 关闭
  • 开始
  • 启动\u失败
  • 开始
  • 关闭
  • 关闭\u失败
  • 以下是
    工厂
    类的当前设计:

    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失败
    时调用,
    stop
    方法只能在
    state==started | state==starting失败
    时调用

    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();
        }
    }
    

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

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

    可能有比使用Thread.sleep for wait更好的解决方案,所有的创建模型都将完成,但我不知道如何轻松完成

    希望这能帮助你

    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();
        }
    }
    

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

    取而代之的是,创建
    工厂
    类的对象,并让所有方法都
    同步

    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();
        }
    }
    

    希望这有帮助。

    无需同步。对状态使用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 {}
    }
    

    使用
    synchronized
    块。您确定
    Factory
    需要使用
    static
    方法吗?看起来您希望在整个应用程序中都有一个
    Factory
    的实例,并且客户端不需要调用
    start
    方法。@LuiggiMendoza是的,您是对的,使用静态方法有那么糟糕吗?我应该使用单例模式吗?有
    static
    方法并不坏,但是
    start
    并不意味着是
    static
    。您可以将您的
    工厂
    设置为枚举,它将是一个单例,并且其初始化将是线程安全的。不过,您应该应用一些技术,使方法的执行是线程安全的。由于您没有提供有关方法的具体细节,我们只能声明您在验证
    工厂
    的状态后,应使用
    同步
    块来实现
    启动
    停止
    方法,而
    create
    方法根本不需要任何同步,除非它修改
    工厂的状态
    。如果
    状态
    仍然是无效状态,您将使用
    if
    检查状态,然后抛出一个
    RuntimeException
    ,指出
    工厂
    尚未初始化。此实现已中断,因为start()、stop()、create()包含争用条件。一般来说,volatile仅适用于以下情况:您希望读取共享值而不更改它,或者您希望以原子方式更改原语值,并且不必关心其当前数字。如果需要,请再次阅读volatile。最高级别的线程安全性来自不变性。读取不可变变量(如volatile或any)既不需要任何安全性,也不需要volatile提供对所有基元类型的原子操作。请再次访问volatile。代码中的问题:操作a)
    if(factoryState==…)
    ;操作b)
    factoryState=nextState
    。如果线程在a)之后但在b)之前暂停,则factoryState可能会在线程继续工作之前收到意外值。这是一个竞争条件。同意竞争条件:),但仍然不同意声明的其他部分,并支持上述评论。但是“创建”方法如何?同步此方法将导致性能下降。但是“创建”方法如何?同步此方法将导致性能缺陷。我已更改代码,以便创建方法不需要同步,并且停止等待所有创建方法完成。