确保所有其他线程在线程调用critical()(k + 1)时间之前已完成对critical()的第k次调用

时间:2018-02-02 18:11:16

标签: java multithreading

我是Java中多线程的新手,并遇到了以下问题:

问题: 线程1到n执行一个名为 critical()的方法。在此之前,他们执行一个名为 uncritical()的方法。它们的同步约束是一次只能有一个执行 critical(),并且所有线程必须在 critical() uncritical()的执行>可以打电话。您可以假设 n 存储在可从所有线程访问的变量 n 中。为线程设计同步机制。所有线程必须执行相同的代码。线程可以多次调用 critical(),并且应该确保线程无法调用 critical() (k + 1)时间,直到所有其他步骤都已完成对 critical() kth 调用。

这是一个想法(我可能完全错了):

public class CriticalMonitor{
    public static int N = 0;

    public CriticalMonitor(int )

    public void uncritical(int threadID){
        System.out.println(“Thread ” + threadID+“: Uncritical!”);
        N--;
        if(N== 0) notifyAll();
     }

    public synchronized void critical(int threadID){
       while(N!=0){
         try{
            wait();
          }catch(InterruptedException e){
            System.out.println(“Critical failed”);
          }
        }
        System.out.println(“Thread ” + threadID+“: Critical!”);

     }
 }

public static class CriticalThread extends Thread{
    private final CriticalMonitor monitor;
    private int threadId;

    public CriticalThread (CriticalMonitor m, int id){
       monitor = m;
       monitor.N++;
       threadId = id;
    }

    public void run(){
       monitor.uncritical(threadId);
       //random number of calls to critical()?
       int rand = (int)(Math.random()*5); 
       while(rand>=0){
         monitor.critical(threadId);
         rand--;
        }
     }
 }

我无法解决的问题是如何在线程调用之前确保所有其他步骤已完成对 critical() kth 调用critical() (k + 1)时间。

2 个答案:

答案 0 :(得分:1)

使用CyclicBarrier

您可以使用线程数n创建CyclicBarrier

  • 要在所有uncritical()之前实施致电critical(),您可以 在await之前让屏障critical()。当所有n个线程都执行uncritical()时,它们将一起跳闸。
  • 实现一个线程无法调用critical()a(k + 1)时间直到全部 其他线程已完成对critical()的第k次调用,我认为你可以调整循环。即使他们不需要拨打critical(), 他们应该致电await。因此,在每一轮中,每个线程都会让障碍知道他们已经达到了这一点。在最后一个到达之后,所有线程将一起进入下一轮。
  • 在CriticalMonitor中,您不再需要wait-notify了 在syncronize方法上使用critical()关键字来保护它,一次只能由一个线程执行。

代码应该是这样的。

public class CriticalThread extends Thread {

    private final CriticalMonitor monitor;
    private int threadId;
    private CyclicBarrier barrier;

    public CriticalThread(CriticalMonitor m, int id, CyclicBarrier barrier) {
        monitor = m;
        monitor.N++;
        threadId = id;
        this.barrier = barrier;
    }

    public void run() {
        monitor.uncritical(threadId);
        //random number of calls to critical()?
        try {
            barrier.await();
            int rand = (int) (Math.random() * 5);
            int time = 0;
            int limit = 5;
            while (time < limit) {
                if (rand > 0) {
                    monitor.critical(threadId);
                    rand--;
                }
                barrier.await();
                time++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用AtomicInteger

首先,您需要设置为AtomicInteger以保证内存可见性。在每个critical中,您需要递减N,而在循环中递增N。

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class CriticalMonitor {
    public static int SOURCE_N = 0;
    public static AtomicInteger N = new AtomicInteger(SOURCE_N);
    public static ReentrantLock lock = new ReentrantLock(true);
    public static Condition condition = lock.newCondition();


    public void uncritical(int threadID) {
        System.out.println("Thread " + threadID + ": Uncritical!");
        N.getAndDecrement();
        if (N.get() == 0) {
            lock.lock();
            try {
                condition.signalAll();
            } finally {
                lock.unlock();
            }

        }
    }

    public void critical(int threadID) {
        lock.lock();
        try {
            while (N.get() != 0) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    System.out.println("Critical failed");
                }
            }
            System.out.println("Thread " + threadID + ":Critical !");
            N.getAndDecrement();
        } finally {
            lock.unlock();
        }
    }
}

CriticalThread

while(rand >= 0){
        monitor.critical(threadId);
        rand--;
        N.getAndIncrement();
        if (N.get() == 0) {
            lock.lock();
            try {
                condition.signal();
            } finally {
                lock.unlock();
            }
        }
 }

答案 1 :(得分:-1)

每次调用uncritical()后,在你的线程上调用yourthreadName.join(),然后调用你的critical()方法。