Наследование от процесса
Простейшим путем для создания процесса является наследование от класса Thread, который имеет все необходимое для создания и запуска процесса. Наиболее важный метод для Thread это run(), который необходимо переопределить чтобы процесс выполнял то, что вам необходимо. Таким образом, run() есть код, который будет запущен "одновременно" с другими процессами в программе.
Следующий пример создает произвольное количество процессов, отслеживаемые по присвоенному каждому процессу уникальному номеру, сгенерированному static переменной. Метод run()от Thread переопределен и выполняет уменьшение счетчика при каждом проходе цикла и завершает выполнение когда счетчик равен нулю (в том месте когда run() возвращает значение процесс завершается).
//: c14:SimpleThread.java
// Very simple Threading example.
public class SimpleThread extends Thread { private int countDown = 5; private static int threadCount = 0; private int threadNumber = ++threadCount; public SimpleThread() { System.out.println("Making " + threadNumber); } public void run() { while(true) { System.out.println("Thread " + threadNumber + "(" + countDown + ")"); if(--countDown == 0) return; } } public static void main(String[] args) { for(int i = 0; i < 5; i++) new SimpleThread().start(); System.out.println("All Threads Started"); } } ///:~
Метод run( ) практически всегда содержит какой-либо тип цикла, выполняемый до тех пор, пока процесс не станет ненужным, поэтому необходимо предусмотреть условие выхода из цикла (или, как в примере выше, просто return из run()). Часто задача run() в выполнении бесконечного цикла, что означает, что кроме исключительных случаев возникновения какого-либо внешнего события завершающющего run(), цикл будет выполняться вечно.
В вызове main( ) содержится несколько созданных и запущенных процессов. Метод start()класса Thread выполняет специальную инициализацию для процесса и затем вызывает run(). Таким образом необходимые действия: вызов конструктора для создания объекта, затем start() конфигурирует процесс и вызов run(). Если не вызвать start() (что делается в конструкторе, если возможно) процесс никогда не будет запущен.
Результат работы программа для одного из запусков ( которые могут отличаться при каждом запуске) следующий:
Making 1 Making 2 Making 3 Making 4 Making 5 Thread 1(5) Thread 1(4) Thread 1(3) Thread 1(2) Thread 2(5) Thread 2(4) Thread 2(3) Thread 2(2) Thread 2(1) Thread 1(1) All Threads Started Thread 3(5) Thread 4(5) Thread 4(4) Thread 4(3) Thread 4(2) Thread 4(1) Thread 5(5) Thread 5(4) Thread 5(3) Thread 5(2) Thread 5(1) Thread 3(4) Thread 3(3) Thread 3(2) Thread 3(1)
Заметьте, что ни где в данном примере не вызывался sleep() и результат работы показывает, что каждый процесс получил часть процессорного времени для выполнения. Это демонстрирует, что sleep(), пока он полагается на существование процесса для того чтобы выполниться, не задействован ни в разрешение, ни в запрещение процесса. Это просто другой метод.
Можно также видеть, чтопроцессы выполняются не в том же порядке в каком они были запущены. Фактически, порядок, в котором CPU обрабатывает существующие процессы, не определен до тех пор, пока не определены приоритеты, используя setPriority() метод класса Thread.
Когда main() создает объекты Thread он не сохраняет ссылки на них. Обычные объекты могут быть просто игрушкой для сборщика мусора, но не Thread. Каждый Thread "регистрирует" себя сам, и таким образом ссылка на него храниться где-то в другом месте из-за чего сборщик мусора не может его очистить.