2015-10-10 2 views
3

С the tutorial Я читаю:Синхронизация Сбой в Java

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

Однако в моем простом примере все еще существует гоночное соревнование для доступа к объекту message.

public class TestThread extends Thread{ 
    int thread; 
    StringBuilder message; 

    public TestThread(int thread, StringBuilder message) { 
     this.thread=thread; 
     this.message=message; 
     start(); 
    } 

    public void run() { 
     synchronized(this){ 
      for (int i=0; i<1000000; i++) { 
       double a=2*2; 
      } 
      modifyMessage(); 
     } 
    } 

    public synchronized void modifyMessage() { 
     message.append(thread); 
    } 
} 

public class TestMultithreading { 
    static TestThread[] testThreads = new TestThread[5]; 

    public static void main(String args[]) { 
     StringBuilder message = new StringBuilder("A"); 
     for (int i=0;i<5;i++) 
      testThreads[i] = new TestThread(i, message); 
     for (int i=0;i<5;i++) 
      try { 
       testThreads[i].join(); 
      } catch (InterruptedException e) {} 
     out.println(message); 
    } 
} 

Я ожидаю, что это есть гарантированный вывод строки длины 6. Однако, время от времени я вижу что-то вроде этого:

A1034 

Это означает, что один из потоков не удалось изменить объект. Может кто-нибудь объяснить мне, почему это происходит и предложить решение проблемы?

ответ

6

Вы уже ответил на свой вопрос:

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

Синхронизированный доступ только к блоку по методу одного и того же объекта, что означает, что в каждом потоке modifyMessage() может быть называется в то же время

Что вы ищете это что-то вроде этого:

for (int i=0; i<1000000; i++) { 
     double a=2*2; 
    } 
    synchronized(message){ 
     modifyMessage(); 
    } 

Теперь метод вызывать только один раз в StringBuilder инстанции.

4

Ваши методы синхронизируются на другом объекте (this).

Если вы измените способ синхронизации на одном объекте, он будет работать. Например.

public void modifyMessage() { 
    synchronized(message) { 
     message.append(thread); 
    } 
} 
Смежные вопросы