Потоки; Создание отдельной ветки, чтобы периодически что-то делать - PullRequest
5 голосов
/ 03 ноября 2010

В дополнение к моему текущему приложению мне нужно создать отдельный поток, который будет периодически выполнять некоторую обработку

Я создал новый класс, чтобы сделать все это, и этот класс будет загружен при запуске моего приложения.

Это то, что я имею до сих пор:

public class PeriodicChecker extends Thread
{
    static
    {
        Thread t = new Thread(new PeriodicChecker());
        while(true)
        {
            t.run();
            try
            {
                Thread.sleep(5000l);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * Private constructor to prevent instantiation
     */
    private PeriodicChecker()
    {

    }

    @Override
    public void run()
    {
        System.out.println("Thread is doing something");
        // Actual business logic here, that is repeated
    }

}

Я хочу сделать конструктор приватным, чтобы другие люди не могли случайно создать экземпляр этого класса. Как мне этого добиться?

Кроме того, есть ли что-то плохое в моей реализации таких требований? Я создаю только один поток, который будет работать, а затем спать, я пропустил что-нибудь очевидное? Я не работал с потоками до

Ответы [ 5 ]

12 голосов
/ 03 ноября 2010

Java предлагает ScheduledExecutorService для планирования и запуска периодических задач или задач с задержкой. Он должен предоставить все функции, которые вам нужны. Timer - это еще один класс, который предлагает аналогичные функции, но я бы порекомендовал ScheduledExecutorService over Timer для его гибкости настройки и лучшего управления ошибками.

10 голосов
/ 03 ноября 2010

В вашем коде есть некоторые концептуальные ошибки ... например:

  • Вы должны вызывать start (), а не run (), потому что вы запускаете метод последовательно, а не одновременно.
  • Вы можете вызывать start () только один раз, а не один раз в каждой итерации цикла.После этого поток находится в состоянии TERMINATED, вы должны создать новый поток для его повторного запуска
  • Не следует создавать поток в статическом блоке, это плохая практика, и, возможно, поток работает раньшеВы хотите, чтобы он работал.

Вы должны прочитать несколько примеров о потоке, его немного сложно понять с самого начала, и вы можете легко получить нежелательные эффекты.

ЗдесьЭто небольшой пример, который может сделать что-то похожее на то, что вы хотите:

public class PeriodicChecker extends Thread
{
    @Override
    public void run()
    {
        while(true) {
           System.out.println("Thread is doing something");
           Thread.sleep(5000);
        }
    }

}

public OtherClass {
   public static void main(String args[]) {
      Thread t = new PeriodicChecker();
      t.start();
   }
}

Если вы хотите, чтобы никто не мог создать новый поток, вы можете создать синглтон, так что вы будете уверены, что никто не создаетбольше тем.

4 голосов
/ 03 ноября 2010

Я бы рекомендовал вам рассмотреть Класс таймера - он обеспечивает функциональность для выполнения периодических задач. Также вы можете взглянуть на «Timer & TimerTask против Thread + sleep в Java» обсуждение вопроса - там вы можете найти некоторые аргументы и примеры.

3 голосов
/ 03 ноября 2010

Прежде всего, чтобы ответить на ваш конкретный вопрос, вы уже достигли своей цели.Вы объявили, что ваш конструктор является закрытым, что означает, что ни один внешний класс не может назвать его как new PeriodicChecker().

Однако, глядя на ваш код, есть ряд других проблем:

Во-первых, высоздание экземпляра вашего класса в его собственном статическом конструкторе.Цель статического конструктора - инициализировать любое статическое состояние, которое может иметь ваш класс, от которого могут зависеть экземпляры вашего класса.Создавая экземпляр класса в статическом конструкторе, все эти гарантии выходят за пределы окна.

Во-вторых, я не думаю, что ваш поток будет вести себя так, как выожидайте, что он будет вести себя, в первую очередь потому, что вы на самом деле не запускаете другой поток :).Если вы намереваетесь начать новый поток, вам нужно вызвать метод start() для этого объекта потока.Вызов run(), как вы делаете, на самом деле не создает новый поток, а просто запускает метод run() в текущем потоке.

В настоящее время, когда вы хотите создать новый поток, чтобы сделать что-то, рекомендуемый способдля достижения этого нужно не расширять Thread, а вместо этого реализовать интерфейс Runnable.Это позволяет вам отделить механизм потока от поведения, которое вы намереваетесь запустить.

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

public class Main {

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    System.out.println("Thread is doing something");
                    Thread.sleep(5000);
                }
            }
        }).start();
    }

}
2 голосов
/ 03 ноября 2010

Это почти никогда право расширять Thread. Если вы когда-нибудь обнаружите, что делаете это, отойдите назад, посмотрите и спросите себя, действительно ли вам нужно изменить способ работы класса Thread.

Почти во всех случаях, где я вижу extends Thread, работу лучше выполнить, внедрив интерфейс Runnable или используя некоторую форму Timer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...