синхронизированные блоки, содержащие вызовы методов, будет ли это работать?

Является ли приведенный ниже код законным для синхронизации myIntArray?
Помешает ли он трем нижним методам изменить myIntArray не по порядку?
Я хочу, чтобы все происходило в порядке отложенный метод1, отложенный метод2, метод3 и чтобы ни один из них не испортился запустившись до того, как предыдущий завершит свои изменения в myIntArray.
Нужны ли для трех нижних объявлений метода ключевые слова synchronized?
Должны ли три нижних метода содержать блоки synchronized(myIntArray)?
Должен ли мой синхронизированный block находиться вокруг Runnable, а не внутри него?
Нужно ли мне уведомлять, ждать или присоединяться к командам?

            public class HelpPlease {

                public int myIntArray[] = new int[100];

                public void chooseSquare() {

                    ...
                    Handler handler=new Handler();
                    final Runnable r = new Runnable()
                    {
                        public void run() 
                        {   
                            synchronized(myIntArray) {
                                delayedMethod1();
                            }
                        }
                    };
                    handler.postDelayed(r, 1000);

                    ...

                    Handler handler2=new Handler();
                    final Runnable r2 = new Runnable()
                    {
                        public void run() 
                        {    
                            synchronized(myIntArray) {
                                delayedMethod2();
                            }
                        }
                    };
                    handler2.postDelayed(r2, 1000);

                    ...

                    synchronized(myIntArray) {
                        method3();
                    }
               }

               public void delayedMethod1() {
                    ...
                    change myIntArray;
                    otherMethodsABC();
               {

               public void delayedMethod2() {
                    ...
                    change myIntArray;
                    otherMethodsDEF();
               }

               public void method3() {
                    ...
                    change myIntArray;
                    otherMethodsGHI();
               }
           }

Дополнительные сведения: Handler/Runnable задерживает создание событий, которые иногда не синхронизируются

РЕДАКТИРОВАТЬ:

Имеет ли это смысл? Запустить поток и дождаться его завершения? Не знаю, как добавить задержку, и в этом весь смысл.

                        //Handler handler=new Handler();
                        final Runnable r = new Runnable()
                        {
                            public void run() 
                            {
                                delayedMethod();
                            }
                        };
                        //handler.postDelayed(r, COMPUTER_MOVE_DELAY);

                        ExecutorService es = Executors.newFixedThreadPool(1);

                        final Future f1 = es.submit(r);

                        try
                           {
                               f1.get();
                           }
                           catch (InterruptedException e)
                           {
                               throw new RuntimeException(e);
                           }
                           catch (ExecutionException e)
                           {
                               throw new RuntimeException(e);
                           }

person NewUserSOF    schedule 05.08.2012    source источник


Ответы (1)


Не пытайтесь сделать это с синхронизированными блоками. Это гарантирует только то, что никакие два блока не будут работать одновременно, а не порядок их запуска. Вам лучше написать «родительский» исполняемый файл, который выполняет отложенные методы в том порядке, в котором вы хотите. В качестве альтернативы вы можете использовать первый метод, когда он будет завершен, опубликовать runnable для запуска второго и т. д., объединив их вместе.

Чтобы быть более конкретным, если вам нужна задержка, а затем для последовательного запуска трех методов, я бы закодировал это так:

public class HelpPlease {
    public int myIntArray[] = new int[100];
    Handler handler=new Handler();

    public void chooseSquare() {
        ...
        final Runnable r = new Runnable()
        {
            public void run() 
            {
                delayedMethod1();
                delayedMethod2();
                method3();
            }
        };
        handler.postDelayed(r, 1000);
    }

    public void delayedMethod1() {
        ...
        change myIntArray;
        otherMethodsABC();
    }

    public void delayedMethod2() {
        ...
        change myIntArray;
        otherMethodsDEF();
    }

    public void method3() {
        ...
        change myIntArray;
        otherMethodsGHI();
    }
}

Нет необходимости в синхронизации вообще. Важно использовать один Handler, чтобы гарантировать, что множественные вызовы chooseSquare() приведут к сериализованному выполнению runnables.

РЕДАКТИРОВАТЬ:

Основываясь на ваших последних комментариях, вот как я буду действовать. Во-первых, создайте один объект Handler, доступный всему вашему коду планирования действий. Чтобы использовать ваши два примера, их можно было бы реализовать следующим образом:

public void chooseSquare() {
    . . .
    if (point_scored) {
        makeSquaresGlow(list_of_squares);
        playSound(sound_to_play);
        handler.postDelayed(new Runnable() {
            public void run() {
                makeSquaresNotGlow(list_of_squares);
            }
        }, 1000L);
    }
    if (time_for_attack(purple)) {
        handler.postDelayed(new Runnable() {
            public void run() {
                launchAttack(purple);
            }
        }, 1000L);
    }
}

Предполагая, что chooseSquare() вызывается в потоке событий, все (включая отложенные вызовы методов) также будет выполняться в том же потоке, поэтому синхронизация не требуется. Могут быть условия гонки (launchAttack и makeSquaresNotGlow будут запланированы одновременно), но handler будет выполняться по одному. Если последовательность этих отложенных действий жизненно важна, вы можете определить «мета» действие Runnable, которое принимает последовательность действий и выполняет их в заданном порядке в будущем.

person Ted Hopp    schedule 05.08.2012
comment
Я мог бы использовать немного больше информации. Все, что я действительно пытаюсь сделать, это иметь задержку в игре. Означает ли родительский runnable что-то вроде ThreadPoolExecutor? или какой-то массив runnables? - person NewUserSOF; 06.08.2012
comment
@NewUserSOF - я добавил пример кода в свой ответ. Я не думаю, что пул потоков вообще необходим для того, что вы хотите. Насколько я понимаю, вы пытаетесь устранить параллелизм (через синхронизацию, которая не работает), а не добавить его, используя несколько потоков. (Кстати, наличие нескольких объектов Handler, вероятно, усугубляет ваши проблемы.) - person Ted Hopp; 06.08.2012
comment
Еще раз спасибо, я не хочу ждать одну задержку, а затем запускать 3 метода. У меня есть различные игровые события (которые могут произойти или не произойти в зависимости от условий игры), для каждого из которых требуется своя задержка. Хотя каждое может происходить не всегда, для них есть порядок, когда они происходят. - person NewUserSOF; 06.08.2012
comment
@NewUserSOF - означает ли это, что вызов chooseSquare() (например) должен инициировать выполнение ряда действий, которые должны выполняться по какому-то расписанию? И что конкретные действия и расписание определяются условиями игры и не могут быть каталогизированы заранее? Кроме того, включают ли эти действия обновление пользовательского интерфейса или изменения состояния игры, которые можно выполнить в рабочем потоке? - person Ted Hopp; 06.08.2012
comment
ChooseSquare будет вызывать различные IF и методы, которые должны выполняться в том порядке, в котором они представлены, некоторые с задержкой в ​​одну секунду. Различные возможные сценарии могут быть определены заранее - они ограничены. Действия во многом связаны с обновлением пользовательского интерфейса (и состояния игры). - person NewUserSOF; 06.08.2012
comment
Например, выберите «Квадрат», они набрали очко?, заставьте квадраты светиться, воспроизведите звук, подождите секунду, а затем запустите сценарий очистки, чтобы очистить квадраты, не пора ли для случайной фиолетовой атаки? если да, подождите секунду, а затем сделайте это, настала ли очередь компьютера делать ход? подождите секунду, а затем дайте ему сделать ход ... - person NewUserSOF; 06.08.2012
comment
@NewUserSOF - я добавил больше к своему ответу, чтобы решить эту проблему. - person Ted Hopp; 06.08.2012
comment
Я перешел на одного обработчика, как вы советуете. Проблема, с которой я сталкиваюсь, заключается в том, что пурпурная атака запускается до завершения очистки. Так что я не просто хочу контролировать порядок событий, я хочу контролировать то, что должно быть завершено, прежде чем начнется другое дело. - person NewUserSOF; 06.08.2012
comment
@NewUserSOF - похоже, вам нужен логический уровень, который обрабатывает такую ​​​​последовательность (где действие включается только при соблюдении определенных предварительных условий). Это не то, с чем вы сможете справиться с умным использованием обработчика и/или синхронизации. (Как я уже сказал в своем редактировании, синхронизация не является фактором, поскольку все уже выполняется в одном потоке). Я бы рекомендовал вам определить конкретные проблемы последовательности, с которыми вы сталкиваетесь, сузить их до относительно простого примера проблемы и опубликовать его как новый вопрос. - person Ted Hopp; 06.08.2012