Java Thread
Наследование от Thread
Простейшим путем для создания процесса является наследование от класса Thread, который имеет все необходимое для создания и запуска процесса. Наиболее важный метод для Thread это run(), который необходимо переопределить чтобы процесс выполнял то, что вам необходимо. Таким образом, run() есть код, который будет запущен "одновременно" с другими процессами в программе.
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");
  }
}
Наследование от Runnable

Использование совмещенной программы-процесса не столь очевидно. Когда запускается программа, создается объект, который Runnable, но процесс не запускается, что должно быть сделано явно.

Когда что-либо имеет интерфейс Runnable, это просто означает, что оно имеет метод run( ), однако ничего особеного в этом нет - не производится ни каких задуманных для процесса действий, кроме как наследование класса от Thread. Таким образом, чтобы сделать процесс из Runnable объекта необходимо создать отдельный объект Thread, как показано выше, передав объект Runnable в специальный конструктор Thread. Затем можно вызвать start() для данного процесса.

public class Counter3 
    extends JApplet implements Runnable {
  private int count = 0;
  private boolean runFlag = true;
  private Thread selfThread = null;
  private JButton 
    start = new JButton("Start"),
    onOff = new JButton("Toggle");
  private JTextField t = new JTextField(10);
  public void run() {
    while (true) {
      try {
        selfThread.sleep(100);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
      if(runFlag) 
        t.setText(Integer.toString(count++));
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(selfThread == null) {
        selfThread = new Thread(Counter3.this);
        selfThread.start();
      }
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    cp.add(t);
    start.addActionListener(new StartL());
    cp.add(start);
    onOff.addActionListener(new OnOffL());
    cp.add(onOff);
  }
  public static void main(String[] args) {
    Console.run(new Counter3(), 300, 100);
  }
}
Процессы демоны

Процесс "демон" это процесс, который выполняет основные сервисный задачи в фоном режиме, так долго, пока запущена основная программа, но не является основной частью программы. Таким образом, когда все процессы не-демона завершаются программа останавливается. И наоборот, пока хоть один процесс не-демон выполняется программа не остановлена. (Как, например, процесс выполняющий main()).

Можно выяснить, является ли процесс демоном через вызов isDaemon( ), и можно установить или отменить параметры для процесса демона функцией setDaemon( ). Если процесс является демоном, то любой созданный им процесс также является демоном.

class Daemon extends Thread {
  private static final int SIZE = 10;
  private Thread[] t = new Thread[SIZE];
  public Daemon() { 
    setDaemon(true);
    start();
  }
  public void run() {
    for(int i = 0; i < SIZE; i++)
      t[i] = new DaemonSpawn(i);
    for(int i = 0; i < SIZE; i++)
      System.out.println(
        "t[" + i + "].isDaemon() = " 
        + t[i].isDaemon());
    while(true) 
      yield();
  }
}

class DaemonSpawn extends Thread {
  public DaemonSpawn(int i) {
    System.out.println(
      "DaemonSpawn " + i + " started");
    start();
  }
  public void run() {
    while(true) 
      yield();
  }
}

public class Daemons {
  public static void main(String[] args) 
  throws IOException {
    Thread d = new Daemon();
    System.out.println(
      "d.isDaemon() = " + d.isDaemon());
    // Allow the daemon threads to
    // finish their startup processes:
    System.out.println("Press any key");
    System.in.read();
  }
}
Группы процессов

Все процессы принадлежат к группам процессов. Это может быть группа процессов по умолчанию, или группа явно указанная при создании процесса. Во время создания процесс привязан к группе и не может сменить ее на другую группу. Каждое приложение имеет, по крайне мере, один процесс, который принадлежит системной группе процессов. При создании нескольких процессов без указания группы, они также будут принадлежать системной группе. Одна группа процессов также может принадлежать другой группе процессов.

Группа процессов, к которой принадлежит только что созданная (не понятно, созданная(ый) кто - группа или процесс - прим. перев.), должна быть указана в конструкторе. Если создается группа процессов без указания группы, к которой она должна принадлежать, то она помещается в системную группу. Таким образом, все процессы приложения в конечном счете имеют системную группу в качестве предка.

Причем доступ возможен только к процессам являющимися подветвью вашей системной группы процессов и, вероятно, это и подразумевают под "безопастностью". Доступ к чужим системным группам не возможен.

Синхронизация методов и объектов

Достаточно простой способ синхронизации потоков, обращающихся к общим критическим ресурсам - это использование синхронизированных методов. Сделать метод синхронизированным можно, объявив его synchronized:

public synchronized void addValue()
{
 . . .
}

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

Можно выполнить синхронизацию не всего метода, а только критичного фрагмента кода:

. . .
synchronized(Account)
{
 if(Account.check(3000000))
   Account.decrement(3000000);
}
. . .

В этом случае от одновременного доступа защищается только объект Account.

Ожидание извещения

Каждый поток может управлять работой других потоков, для чего в Java имеются методы wait, notify и notifyAll, определенные в классе Object. Метод wait может использоваться либо с параметром, либо без параметра. Он переводит поток в состояние ожидания. В этом состоянии поток будет находиться до тех пор, пока не будет вызван извещающий метод notify, или notifyAll, или же пока не истечет время, указанное в параметре метода wait. Метод, который будет переводиться в состояние ожидания, должен быть синхронизированным, т. е. его следует описать как synchronized:

public synchronized void run()
{
 try
 {
  Thread.wait();
 }
 catch (InterruptedException e)
 {
 }
 while (true)
 {
  . . .
 }
}

В этом примере внутри метода run определен цикл. Перед его запуском метод run переводится в состояние ожидания до тех пор, пока другой поток не пошлет ему извещение с помощью метода notify. А вот пример вызова метода notify:

synchronized(SleepingThread)
{
 SleepingThread.notify();
}

Обратите внимание, что вызов метода notify выполняется в синхронизированном режиме. В качестве объекта синхронизации выступает поток, для которого вызывается метод notify.

Ожидание завершения потока

Еще одно средство синхронизации - это метод join. С помощью join можно выполнять ожидание завершения потока, для которого этот метод вызван.

Блокировки

Вы должны знать что sleep() и suspend() не освобождают блокировку во время своего вызова. С другой стороны, метод wait( ) освобождает блокировку во время своего вызова, что означает, что другие, synchronized методы в объекте процесса могут быть вызваны во время wait().

Если поток ожидает какой-либо активности по вводу/выводу, то он автоматически блокируется.


Hosted by uCoz