8

我有以下类型的代码:

synchronized block1 {
    //only one thread in the block
}

{lot of code where synchronization not necessary}

synchronized block2 {
    //only one thread in the block. 
    //All the threads that executed block1 before this thread should have already executed this block.
}

每个线程首先以相同的顺序执行块 1、非同步块和块 2。

如果线程 T1 在线程 T2 之前执行 block1,那么 T1 应该在 T2 之前执行 block2。有两个以上的线程。

有没有办法在java中实现这一点?

4

4 回答 4

2

这基本上创建了一个队列,线程将等待它们的数量出现。[更新]

private AtomicInteger place = new AtomicInteger(0);
private AtomicInteger currentPlaceInQueue = new AtomicInteger(0);
private ReentrantLock lock = new ReentrantLock();
private Condition notNext = lock.newCondition();

public void method() {

   ThreadLocal position = new ThreadLocal();

   synchronized(this) {
      //Your code
      position.set(place.getAndIncrement());
   }

   // More code

   lock.lock();
   while ((int) currentPlaceInQueue.get() != position.get()) {
      notNext.await();
   }
    // More code
   lock.unlock();
   currentPlaceInQueue.getAndIncrement();
   notNext.notifyAll();
 }
于 2015-09-02T12:59:32.877 回答
2

据我了解,关键部分 #2 必须以与关键部分 #1 相同的顺序执行

如果线程 T1 在线程 T2 之前执行 block1,那么 T1 应该在 T2 之前执行 block2。有两个以上的线程。

然后可以使用队列来确保执行顺序。

private Object lock = new Object();
private Queue<Thread> threadQueue = new ArrayDeque<>();

// https://stackoverflow.com/questions/32353283/synchronization-threads-execute-two-critical-sections-in-same-order
public void executeCriticalSectionsInOrder() throws InterruptedException {
    // Critical Section #1
    synchronized (lock){
        // synchronized code #1

        // Add self to queue
        threadQueue.add(Thread.currentThread());
    }

    // {lot of code where synchronization not necessary}

    // Critical Section #2
    synchronized (lock) {
        //All the threads that executed block1 before this thread should have already executed this block.
        // Wait turn
        Thread t = threadQueue.element(); // Do not remove until it is self
        while (t != Thread.currentThread()) {
            lock.wait();
            // After sleep try again
            t = threadQueue.element();
        }
        // Verified own turn. Update status
        threadQueue.remove();

        // synchronized code #2

        lock.notifyAll(); // Awake any waiting thread after exiting section.
    }

但是,如果一个线程死亡/退出而没有将自己从队列中移除,那么后续线程将被无限期地阻塞。也许添加一个 finally 块来做家务?

注意:在Nicholas Robinson 的回答中,建议使用位置顺序而不是队列,这似乎更有效。

于 2015-09-02T13:49:20.883 回答
0

synchronized您示例中的块是红鲱鱼。您的问题是,您有 N 个线程,并且您有两个代码块,并且您希望确保在所有线程都完成第一个块之前没有一个线程进入第二个块。

CyclicBarrier为此使用 a 。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

于 2015-09-07T22:47:47.807 回答
-2

您应该能够Lock在调用之前使用 a 并在调用block1之后释放block2

static Lock lock = new ReentrantLock();
Random random = new Random();

public void block1() throws InterruptedException {
    System.out.println("Enter block 1");
    Thread.sleep(random.nextInt(500));
    System.out.println("Leave block 1");
}

public void block2() throws InterruptedException {
    System.out.println("Enter block 2");
    Thread.sleep(random.nextInt(500));
    System.out.println("Leave block 2");
}

private class BlockTester implements Runnable {

    long start = System.currentTimeMillis();

    @Override
    public void run() {
        while (System.currentTimeMillis() < start + 10000) {
            lock.lock();
            try {
                System.out.println("Thread: " + Thread.currentThread().getName());
                block1();
                block2();
            } catch (InterruptedException ex) {
                System.out.println("Interrupted");
            } finally {
                lock.unlock();
            }
        }
    }
}

public void test() throws InterruptedException {
    Thread[] blockTesters = {
        new Thread(new BlockTester()),
        new Thread(new BlockTester()),
        new Thread(new BlockTester()),
        new Thread(new BlockTester()),
        new Thread(new BlockTester())
    };
    for (Thread t : blockTesters) {
        t.start();
    }
    for (Thread t : blockTesters) {
        t.join();
    }

}
于 2015-09-02T12:46:26.963 回答