2013-10-06 5 views
0

Просто для практики я хотел реализовать Java-синхронизированное ключевое слово как объект java. Не могли бы вы сказать, что код ниже - хороший дизайн для этого? Я предполагаю, что AtomicReference будет иметь аналогичную производительность AtomicBoolean?Является ли это хорошим дизайном для реализации ключевого слова java synchronized в качестве объекта?

Обновленный код после предложений:

public class SynchronizedBlock implements Runnable{ 

private final Lock lock; 
private final Runnable runnable; 

public SynchronizedBlock(Runnable r, Lock l){ 
    runnable = r; 
    lock = l; 
} 

public void run() { 
    try { 
     while(!lock.compareAndSet(false, true)){ 
      Thread.sleep(100); 
     } 
     runnable.run(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } finally { 
     lock.unlock(); 
    } 


} 

} 

public class Lock { 
private final AtomicReference<Boolean> locked = new AtomicReference<Boolean>(false); 

public boolean compareAndSet(boolean expected, boolean update){ 
    return locked.compareAndSet(expected, update); 
} 

public boolean isLocked(){ 
    return locked.get(); 
} 

public void unlock(){ 
    locked.set(false); 
} 
} 

@Test 
public void test() { 



    final SynchronizedBlock sb = new SynchronizedBlock(new Runnable(){ 

     public void run() { 
      x++; 
      System.out.println(x); 
     } 

    }, new Lock()); 

    Runnable r1 = new Runnable(){ 

     int c = 0; 
     public void run() { 
      while(c<10){ 
       sb.run(); 
       c++; 
      } 
     } 

    }; 

    Runnable r2 = new Runnable(){ 

     int c = 0; 
     public void run() { 
      while(c<10){ 
       sb.run(); 
       c++; 
      } 
     } 

    }; 

    Thread t1 = new Thread(r1); 
    Thread t2 = new Thread(r2); 

    t1.start(); 
    t2.start(); 

    while (t1.isAlive() && t2.isAlive()){ 

    } 

    assertEquals(20,x); 

} 
+0

Использование Thread.sleep() для этой задачи сильно обескуражено. –

+0

Не могли бы вы объяснить, почему это? – newlogic

+0

он приносит ненужную задержку. Вместо этого используйте http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html. –

ответ

1

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

Я бы удалил метод блокировки и поместил разблокировку в конце блокировки, чтобы исключение/ошибка не приводило к блокировке, которая никогда не разблокируется.

Кроме того, я хотел бы использовать AtomicBoolean, который является более естественным, чем AtomicReference

+0

Привет, я обновил код и смог его сломать, мой модульный тест (см. Новый код выше) теперь прерывается с перерывами. Есть идеи? его либо прохождение, либо провал с разницей в 10. – newlogic

+1

Я бы все равно использовал AtomicBoolean. Не знаете, как и почему он будет терпеть неудачу. Кажется, у вас достаточно барьеров чтения/записи для 'x', чтобы быть правильно между потоками. –

+1

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

0

Во-первых, и самое главное, вы должны удалить Thread.sleep(100). Это приведет к задержке не менее 100 мс даже в случае только двухпотоковых конфликтов.

Чтобы упростить код, вы можете просто использовать AtomicBoolean вместо AtomicReference. Также, если вы действительно обеспокоены параллелизмом в ситуации с высоким уровнем конкуренции, вы можете изменить свой код, чтобы проверить, заблокирован ли он перед выполнением CAS.

while (true) { 
    if (lock.isLocked()) continue; // or get() == true if you use AtomicBoolean 
    if (lock.compareAndSet(false, true)) 
    break; 
} 

Это является примером TTAS (Test-Test-And-Set) запирающим который использует местное формование, чтобы уменьшить доступ основной памяти во время цикла. См. http://en.wikipedia.org/wiki/Test_and_Test-and-set

+0

Приветствия, человек, которому я поставил спать, - это освободить процессор, я не хочу голодать другие потоки. Во время высоких периодов конкуренции. Как бы вы решили эту проблему? – newlogic

+0

@ user1037729 Я думаю, что я слишком поздно, чтобы ответить, но я бы предпочел настроить приоритет потока или попробовать еще заранее. Профиль темы "и посмотреть, как они себя ведут. – yhpark

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

  • Нет связанных вопросов^_^