【问题标题】:blocking threads in java using semaphore使用信号量阻塞java中的线程
【发布时间】:2015-10-05 21:40:00
【问题描述】:

我的目标是让多个线程同时访问一个静态属性“nbPlace”,并减少它。我使用变量“mutex”让一个线程每次递减,但是出了点问题。这是我的代码:

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();

}

}

【问题讨论】:

  • 为什么不把你的decrementer方法设为synchronized
  • “出了点问题”你能说得更具体点吗?
  • 是否有充分的理由不使用 AtomicInteger 或 CountdownLatch?或者信号量,就此而言。
  • 我期待所有线程减量 "nbPlace" ,但只有第一个做到了。
  • 如果你让它变得易变有帮助吗? (还有互斥锁)

标签: java multithreading synchronization


【解决方案1】:

安迪·特纳在 cmets 中所说的正确使用倒计时锁

我不同意接受的答案,因为如果 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();
        }
    }
}

我从来没有使用过信号量,所以我不能谈论它们。

【讨论】:

    【解决方案2】:

    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();
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果一个线程在另一个线程位于该块中时达到if (mutex==1) { 条件,它会跳转到else 并调用join()

      在当前线程(而不是另一个线程)上调用join()意味着当前线程正在等待自己死亡,这是不可能发生的,所以这些线程永远阻塞。

      【讨论】:

        【解决方案4】:

        不,在 Java 中事情不是这样工作的。如果没有适当的同步,您将无法同时访问可变数据。

        让这段代码安全的最简单方法:

        static int nbPlace = 10;
        static final Object object = new Object();
        
        public Client(String name) {
            super(name);
        }
        
        public void run() {
            synchronized (object) {
                decrementer(getName());
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多