Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
курсовик.doc
Скачиваний:
18
Добавлен:
08.02.2015
Размер:
326.14 Кб
Скачать

3. Приоритеты потоков

Каждый поток в системе имеет свой приоритет. Приоритет – это некоторое число в объекте потока, более высокое значение которого означает больший приоритет. Система в первую очередь выполняет потоки с большим приоритетом, а потоки с меньшим приоритетом получают процессорное время только тогда, когда их более привилегированные собратья простаивают.

Работать с приоритетами потока можно с помощью двух функций: void setPriority(int priority)– устанавливает приоритет потока. Возможные значения priority — MIN_PRIORITY, NORM_PRIORITY и MAX_PRIORITY. int getPriority() – получает приоритет потока.

Некоторые полезные методы класса Thread работы с потоками. boolean isAlive()— возвращает true если myThready() выполняется и false если поток еще не был запущен или был завершен.setName(String threadName)– Задает имя потока.String getName()– Получает имя потока. Имя потока – ассоциированная с ним строка, которая в некоторых случаях помогает понять, какой поток выполняет некоторое действие. Иногда это бывает полезным.static Thread Thread.currentThread()— статический метод, возвращающий объект потока, в котором он был вызван.long getId()– возвращает идентификатор потока. Идентификатор – уникальное число, присвоенное потоку.

4. Проблемы при реализации параллельных программ

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

4.1 Взаимная блокировка (deadlock)

Возникает когда несколько потоков при попытки синхронизации по нескольким точкам блокируются в ожидании другу друга. Например один поток владеет одной точкой синхронизации, второй другой и каждый из них ожидает захвата точки которая уже захвачена. Это происходит по причине неконтролируемого порядка захвата точек синхронизации, что не всегда возможно в большом приложении. Данная проблема имеет несколько способов решения: автоматическое детектирование взаимной блокировки и принятие мер по её устранению, захватывать точку синхронизации без постоянной блокировки механизма захвата, жёстко гарантировать порядок захвата. Нужно учитывать, что эта проблема характерна для любого механизма синхронизации который может блокировать текущий поток навсегда. Рассмотрим простейший пример взаимной блокировки.

Пример 10.

public class DeadLock {

     public static void main(String[] args) {

        final ReentrantLock lock1 = new ReentrantLock();

        final ReentrantLock lock2 = new ReentrantLock();

        Thread t = new Thread(new Runnable() {

            @Override

            public void run() {

                lock1.lock();

                delay();

                lock2.lock();

                try {

                    //критическая секция

                }

                finally {

                    lock1.unlock();

                    lock2.unlock();

                }

            }

        }, "slave");

         t.start();

         lock2.lock();

        delay();

        lock1.lock();

        try{

            //критическая секция

        }

        finally {

            lock2.unlock();

            lock1.unlock();

        }

        System.out.println("finished");

    }

     /**

     * Задержка на 1 секунду

     */

    public static void delay() {

        try {

            Thread.sleep(1000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

Выполнение кода представленного выше никогда не приведёт к выводу на экран строки "finished". Потоки main и slave будут заблокированы навсегда после того как первый захватит lock1, а второй lock2. В таком маленьком фрагменте кода не вызовет проблем детектировать взаимную блокировку просто посмотрев листинг. В реальности не всегда получается это сделать на этапе разработки (хотя возможно использовать статический анализатор кода), поэтому требуются методы детектирования таких ситуаций во время выполнения. Наиболее удобным методом является изучения дампа потоков, который можно получить с помощью утилиты jstack, либо послав сигнал выполняемому процессу (для консольного windows приложения Ctrl+Break, в linux сигнал SIGQUIT). Для нашего примера часть дампа потоков будет выглядеть подобно представленному ниже.

Пример 11.

Found one Java-level deadlock:

=============================

"slave":

  waiting for ownable synchronizer 0x2299c870,

  (a java.util.concurrent.locks.ReentrantLock$NonfairSync),

  which is held by "main"

"main":

  waiting for ownable synchronizer 0x2299c848,

  (a java.util.concurrent.locks.ReentrantLock$NonfairSync),

  which is held by "slave"

 Java stack information for the threads listed above:

===================================================

"slave":

        at sun.misc.Unsafe.park(Native Method)

        - parking to wait for  <0x2299c870>

        (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

        at java.util.concurrent.locks.LockSupport.park(Unknown Source)

 ... опущена часть вывода несущественная в контексте обсуждения

        at java.lang.Thread.run(Unknown Source)

"main":

        at sun.misc.Unsafe.park(Native Method)

        - parking to wait for  <0x2299c848>

        (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

        at java.util.concurrent.locks.LockSupport.park(Unknown Source)

... опущена часть вывода несущественная в контексте обсуждения

        at kz.pnhz.test.sandbox.DeadLock.main(DeadLock.java:31)

 

Found 1 deadlock.

... опущена часть вывода несущественная в контексте обсуждения

Таким образом возможно с легкостью распознать причину взаимной блокировки. Хотя deadlock часто выявляется во время выполнения по причине возникновения это ошибка проектирования или реализации приложения и должна исправляться на этапе разработки.