2015-10-05 18 views
-1

我的目標是讓許多線程訪問靜態屬性「nbPlace」,並將其遞減。我使用一個變量「互斥體」來讓一個線程每次都遞減,但是出錯了。這裏是我的代碼:使用信號屏蔽java中的線程

public class Client extends Thread{ 

static int nbPlace=10; 
static int mutex=1; 

public Client(String name){ 
    super(name); 
} 
public void run(){ 
    if (mutex==1) { 
     mutex=0; 
     decrementer(getName()); 
     mutex=1; 
    } else 
     try { 
      join(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

} 
static void decrementer(String nomThread){ 
    nbPlace--; System.out.println("dec par "+nomThread+" ... nbplace="+nbPlace); 
} 
public static void main(String[] args) { 
    // TODO Auto-generated method stub 
Client [] t= new Client[5]; 
for(int i=0;i<5;i++) t[i]=new Client ("thread n° "+i); 
for (int i=0;i<5;i++) t[i].start(); 

} 

}

+0

爲什麼不只是讓你的'遞減'方法'同步'? –

+1

「出了問題」你能更具體嗎? –

+1

有沒有理由不使用AtomicInteger或CountdownLatch?或者是信號量。 –

回答

0

的Java已經有一個信號量的實現,只是用它:

public class Client extends Thread{ 

    static int nbPlace=10; 
    private final Semaphore sem = new Semaphore(1); 

    public Client(String name){ 
     super(name); 
    } 
    public void run(){ 
     try { 
      sem.acquire(); 
      decrementer(getName()); 
      sem.release(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
    static void decrementer(String nomThread){ 
     nbPlace--; System.out.println("dec par "+nomThread+" ... nbplace="+nbPlace); 
    } 
    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
    Client [] t= new Client[5]; 
    for(int i=0;i<5;i++) t[i]=new Client ("thread n° "+i); 
    for (int i=0;i<5;i++) t[i].start(); 
    } 
} 
0

如果一個線程碰到if (mutex==1) {條件時,另一個線程在該塊,它跳到else並調用join()

在當前線程(不在另一線程上)調用join()意味着當前線程正在等待自己死亡,這是不可能發生的,所以這些線程永遠阻塞。

+0

謝謝,這是解釋真正發生的事情:) – ghassen92

0

不,在Java中,事情並不適用。如果沒有正確的同步,您將無法同時訪問可變數據。

,使這個代碼胎面安全的最簡單的方法:

static int nbPlace = 10; 
static final Object object = new Object(); 

public Client(String name) { 
    super(name); 
} 

public void run() { 
    synchronized (object) { 
     decrementer(getName()); 
    } 
} 
1

什麼安迪·特納在評論中說的是正確的使用倒計時鎖存器

我不同意接受的答案,因爲如果try catch失敗,那麼信號量將永遠不會釋放。你應該總是在finally塊中釋放。鎖定代碼最簡單的方法是同步塊。

public synchronized void myMethod(){ 
    //anything here is only able to be run by one thread at a time 
} 

同步的另一種形式是

public class MyClass { 
final Object lock = new Object(); 
public void myMethod(){ 
    synchronized(lock){ 
     //anything here is only able to be run by one thread at a time 
    } 
} 

你也可以使用一個可重入鎖

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class MyClass{ 
    final Lock lock = new ReentrantLock(); 
    public void myMethod(){ 
     lock.lock(); 
     try{ 
      //anything here is only able to be run by one thread at a time 
     }finally{ 
      lock.unlock(); 
     } 
    } 
} 

再有就是它允許只要無限線程讀取,一個線程ReadWriteLock中沒有寫鎖

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReadWriteLock; 
import java.util.concurrent.locks.ReentrantReadWriteLock; 

public class MyClass { 
    final ReadWriteLock rwlock = new ReentrantReadWriteLock(); 
    public void myReadMethod(){ 
     Lock lock = rwlock.readLock(); 
     lock.lock(); 
     try{ 
      //anything here is only able to be run 
      //by any thread that is reading as long 
      //as another thread doesn't have the write lock 
     }finally{ 
      lock.unlock(); 
     } 
    } 

    public void myWriteMethod(){ 
     Lock lock = rwlock.writeLock(); 
     lock.lock(); 
     try{ 
      //anything here is only able to be run by one thread at a time 
     }finally{ 
      lock.unlock(); 
     } 
    } 
} 

我從來沒有使用過信號量,所以我不能對它們說話。