2014-10-09 4 views
3

Я новичок в Computer Science, и я читаю книгу, в которой представлены потоки и мьютексы. Я пробовал программировать мьютекс в Java, который, кажется, работает большую часть времени, но каждый так часто не будет.Программирование мьютексов в Java

В моем коде критический раздел добавляет числа от 1 до 10 к статической переменной j, что приводит к 55 (если j начинается с 0). Если я запускаю три потока одновременно через критический раздел, я получаю случайные конечные значения j, что имеет смысл.

Но с мьютексом ниже, большую часть времени я получаю конечное значение j 165 (55 * 3), которое я хочу, но иногда я получаю случайные значения j. Может ли кто-нибудь взглянуть на мой код и посмотреть, что происходит? Благодаря!

public class Mythread extends Thread { 

    private static int j = 0; 
    private static int mutex = 0; // Initial value of the mutex is 0; 

    @Override 
    public void run() { 


     while (test_and_set(mutex) == 1) { 

      // wait here if mutex is 1 
      System.out.println("Thread waiting.."); 
     } 

     for (int i = 1; i <= 10; i++) { // Start of Critical section 
      j += i;      // 

     } 
     System.out.println(j);  // End of Critical section 
            // Should add on 55 to j if one thread is running through the CS 

     mutex = 0; // Thread that has finished the CS sets the mutex to 0. 

    } 

    public static int test_and_set(int oldMutexValue) { 
     if (mutex == 0) { 
      mutex = 1; 
     } 
     return oldMutexValue; 
    } 


} 

public class Test1 { 




    public static void main(String[] args) { 

     Mythread thread1 = new Mythread(); 
     Mythread thread2 = new Mythread(); 
     Mythread thread3 = new Mythread(); 
     thread1.start(); 
     thread2.start(); 
     thread3.start(); 

    } 



} 
+4

Ваши критические разделы не защищены какой-либо синхронизацией. –

+0

@MarkW 'volatile' не помогло бы в' test_and_set'. Действие не является атомарным. –

+0

Хороший звонок @SotiriosDelimanolis –

ответ

0

Вы создаете условия гонки и используя блокировку спиннинг. Прядильные замки не рекомендуется на Java. Учитывайте следующее:

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

Чтобы исправить:

Реализовать синхронизированный методологии Java. Синхронизированный - это внутренний метод Java для управления потоковой безопасностью и контролем. Нет вращающихся замков!

Изменения MyThread на следующее:

public class MyThread extends Thread { 
private static int j = 0; 

public void run() { 
    synchronized(this) { 
     for (int i = 1; i <= 10; i++) { 
      j += i; 
     } 
    } 
    System.out.println(j); 
} 

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

Остальная часть вашего кода будет работать одинаково!

Надеюсь, это поможет!

+1

Хороший ответ, но не на вопрос, который задал ОП. OP не хочет использовать 'synchronized': он/она пытается узнать, как работает' synchronized', написав свою собственную версию. –

+1

'synchronized (this)' на самом деле не помогает здесь. Множественные потоки должны синхронизироваться на сингулярном общем объекте. – Radiodef

0

Существует java.util.concurrency.Semaphore класс для вашей задачи:

package test; 

import java.util.concurrent.Semaphore; 
import java.util.concurrent.TimeUnit; 

public class MyThread extends Thread { 
    private static int j = 0; 
    private static final Semaphore mutex = new Semaphore(1, true); 

    @Override 
    public void run() { 
     try { 
      while (!mutex.tryAcquire(100, TimeUnit.MILLISECONDS)) { 
       System.out.println("Thread waiting."); 
      } 
     } 
     catch (InterruptedException e) { 
      System.out.println("Thread interrupted."); 
      return; 
     } 

     try { 
      for (int i = 1; i <= 10; i++) { // Start of Critical section 
       j += i;      // 

      } 
      System.out.println(j);  // End of Critical section 
      // Should add on 55 to j if one thread is running through the CS 
     } 
     finally { 
      mutex.release(); // Thread that has finished the CS sets the mutex to 0. 
     } 
    } 
} 
1

(1) Функция test_and_set() выглядит так, как будто она должна эмулировать аппаратную инструкцию с тем же именем, которая использовалась во многих компьютерных архитектурах. Но что должен вернуть test_and_set()? Подсказка. Он должен сообщить вызывающему, действительно ли вызывающий абонент «выиграл» мьютекс.

(2) Проблема с test_and_set() связана с большими проблемами. Это не атомная. Если вы задавались вопросом, почему компьютер, который имеет «тестовые» инструкции и «установленные» инструкции, также должен иметь инструкцию test_and_set (a.k.a., TAS), это потому, что команда TAS атома. Я предполагаю, что вам нужно больше узнать о том, что это значит (см. 4, ниже).

(3) TAS является архаичным. Современные компьютеры реализуют что-то под названием Compare and Swap, Compare и Set (CAS), которое является более мощным.Если вы хотите узнать, как работают современные алгоритмы синхронизации, вы должны использовать CAS вместо TAS.

Стандартная библиотека Java имеет реальную, действительно атомную функцию CAS, которую вы можете вызвать: это java.util.concurrent.atomic.AtomicInteger.CompareAndSet (...). http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html

(4) Вы, вероятно, не следует пытаться научиться писать функции синхронизации/объекты до тех пор, пока у них больше опыта с помощью их. Что вас выводит, так это то, что вы не синхронизировали функцию test_and_set(). Если вы этого не знали, то у вас мало опыта написания многопоточного кода.

Узнать, как использовать объекты синхронизации сначала. http://docs.oracle.com/javase/tutorial/essential/concurrency/После этого вы можете беспокоиться о том, как они реализованы.

Смежные вопросы