简体   繁体   中英

Fine-tuning Java synchronized block behavior

I have two synchronized blocks of code. I need the two blocks of code not to be able to be running simultaneously in two or more different threads, but I would like to allow two or more different threads to run one of the blocks of code simultaneously. How can this be done in Java? To exemplify:

class HelloWorld {

    method1() {
        synchronized (?) { //block 'A'
            //I want to allow 2+ threads to run this code block simultaneously
        }
    }

    method2() {
        synchronized (?) { //block 'B'
            //this should block while another thread is running
            //the synchronized block 'A'
        }
    }

I don't want both synchronized blocks to lock on the same object/class, because that would disallow the first block from being run by multiple threads simultaneously. However, it is the only way I know of to prevent block A and B from running simultaneously by 2 or more threads. There must be a way to achieve this.

I suggest to look into the ReadWriteLock respectively the implementing class ReentrantReadWriteLock . That thing is espeically designed to allow multiple "reader" threads; but only one "writer" thread.

If i read your question correctly, that is exactly what you are asking for. On the other hand, it might also be wise to step back and eloborate what the real problem is that you are trying to solve here.

Especially given the fact that the aforementioned lock works nicely with Java8, but saw problems in earlier version of Java.

Maybe something like:

private CommonStateSynchronizer synchronizer = new CommonStateSynchronizer();

public void method1() throws InterruptedException
{
    synchronizer.run("method1", () -> {
        // do method1
    });
}

public void method2() throws InterruptedException
{
    synchronizer.run("method2", () -> {
        // do method2
    });
}

public static class CommonStateSynchronizer
{
    private final ReentrantReadWriteLock rw;
    private final ReentrantReadWriteLock.ReadLock r; // hold read lock while executing in current state
    private final ReentrantReadWriteLock.WriteLock w; // hold write lock while checking or changing state
    private final Condition stateChanged;
    private volatile String currentState; // do not modify unless holding write lock

    public CommonStateSynchronizer()
    {
        rw = new ReentrantReadWriteLock(true);
        r = rw.readLock();
        w = rw.writeLock();
        stateChanged = w.newCondition();
    }

    public void run(String state, Runnable runnable) throws InterruptedException {
        w.lock();

        while (!state.equals(currentState))
        {
            if (currentState == null)
            {
                currentState = state;
                stateChanged.notifyAll();
                break;
            }
            stateChanged.await();
        }
        assert state.equals(currentState);

        // downgrade to concurrent read lock
        r.lock();
        w.unlock();

        try
        {
            runnable.run();
        }
        finally
        {
            r.unlock();
            w.lock();

            if (rw.getReadLockCount() == 0)
            {
                currentState = null;
                stateChanged.notifyAll();
            }
            w.unlock();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM