user5134749
user5134749

Reputation:

synchronization : Threads execute two critical sections in same order

I have the following kind of code:

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.
}

Each thread first executes block1, non synchronized block, and block2 in that same order.

If thread T1 executes block1 before thread T2, then T1 should execute block2 before T2. There are more than two threads.

Is there a way to achieve this in java?

Upvotes: 8

Views: 1076

Answers (4)

Solomon Slow
Solomon Slow

Reputation: 27115

The synchronized blocks in your example are a red herring. Your problem is, you have N threads, and you have two blocks of code, and you want to make sure that none of the threads enters the second block until all of them have finished the first block.

You use a CyclicBarrier for that. http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

Upvotes: 0

Nicholas Robinson
Nicholas Robinson

Reputation: 1419

This basically creates a queue that threads will wait in until their number comes up. [UPDATED]

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

Upvotes: 2

Javier
Javier

Reputation: 678

As I understand Critical Section #2 MUST be executed in the same order as Critical Section #1

If thread T1 executes block1 before thread T2, then T1 should execute block2 before T2. There are more than two threads.

Then a Queue might be used to ensure the order of execution.

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.
    }

However If one thread dies/exits without removing itself from the queue, then following threads will be blocked indefinetely. Maybe add a finally block to do the housekeeping?

Note: In Nicholas Robinson's answer a position order was suggested instead of a queue, which seems slightly more efficient.

Upvotes: 2

OldCurmudgeon
OldCurmudgeon

Reputation: 65811

You should be able to use a Lock which you take before calling block1 and release after calling 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();
    }

}

Upvotes: -2

Related Questions