Is this Java thread locking concept bad?

java lock
java synchronized
java lock vs synchronized
java object lock
synchronized(this) vs synchronized(object)
mutually exclusive lock java thread
java synchronized block
synchronized lock java

I will try to briefly explain a thread locking concept which I came up with using an example. Consider the following example program.

public class Main {
    public static void main(String[] args) {
        Data data = new Data();

        while (true) {
            doStuff();
            doStuff();

            for (int i = 0; i < 256; i++) {
                System.out.println("Data " + i + ": " + data.get(i));
            }

            doStuff();
            doStuff();

            for (int i = 0; i < 256; i++) {
                data.set(i, (byte) (data.get(i) + 1));
            }

            doStuff();
            doStuff();
        }
    }

    public static void doStuff() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Data {
    private final byte[] data = new byte[256];

    public byte get(int i) {
        return data[i];
    }

    public void set(int i, byte data) {
        this.data[i] = data;
    }
}

It is important that only the main thread modifies data. Now I want to make the loop which prints data asynchronous.

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Data data = new Data();

        while (true) {
            doStuff();
            doStuff();

            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 256; i++) {
                        System.out.println("Data " + i + ": " + data.get(i));
                    }
                }
            });

            doStuff();
            doStuff();

            for (int i = 0; i < 256; i++) {
                data.set(i, (byte) (data.get(i) + 1));
            }

            doStuff();
            doStuff();
        }
    }

After submitting the task to the executorService the main thread can now move on working as desired. The problem is, that the main thread can potentially reach the point where it modifies data before it was printed but the state of data should be printed when it was submitted.

I know in this case I can create a copy of data before submitting which is printed but that's really not what I want to do. Keep in mind that this is just an example and copying could be an expensive operation in the real code.

This is the solution I came up with for this problem.

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Data data = new Data();
        Lock lock = new Lock(); // <---------------

        while (true) {
            doStuff();
            doStuff();

            lock.lock(); // <---------------
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 256; i++) {
                        System.out.println("Data " + i + ": " + data.get(i));
                    }

                    lock.unlock(); // <---------------
                }
            });

            doStuff();
            doStuff();

            lock.waitUntilUnlock(); // <---------------
            for (int i = 0; i < 256; i++) {
                data.set(i, (byte) (data.get(i) + 1));
            }

            doStuff();
            doStuff();
        }
    }

public class Lock {
    private final AtomicInteger lockCount = new AtomicInteger();

    public void lock() {
        lockCount.incrementAndGet();
    }

    public synchronized void unlock() {
        lockCount.decrementAndGet();
        notifyAll();
    }

    public synchronized void waitUntilUnlock() {
        while (lockCount.get() > 0) {
            try {
                wait();
            } catch (InterruptedException e) {

            }
        }
    }
}

Now the main thread can move on working on other stuff after submitting data. At least it can until it reaches the point where it modifies data.

The question: Is this a good or a bad design? Or is there a better (already existing) implementation for this problem?

Note that ReentrantLock wont work in this case. I have to lock before submitting on the main thread and release the lock on the executor thread.


Java has higher-level synchronization abstractions. In general, you should really avoid wait() and notifyAll(), which are too low-level and complex to use correctly and read.

In this case, you could just use a shared blocking queue (a synchronous queue looks appropriate to me) between both threads:

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Data data = new Data();
    SynchronousQueue queue = new SynchronousQueue();

    while (true) {
        doStuff();
        doStuff();

        executorService.submit(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 256; i++) {
                    System.out.println("Data " + i + ": " + data.get(i));
                }
                queue.put(data);
            }
        });

        doStuff();
        doStuff();

        data = queue.take();
        for (int i = 0; i < 256; i++) {
            data.set(i, (byte) (data.get(i) + 1));
        }

        doStuff();
        doStuff();
    }

Object level lock vs Class level lock in Java, It is illegal and result in compilation error. Do not synchronize on non final field on synchronized block in Java. because reference of non final field may change any time and then different thread might synchronizing on different objects i.e. no synchronization at all. Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example:


You want this Data thing to be built asynchronously, and the main thread wants to be able to proceed to a certain point, then needs to get the completed object. This is what Futures are for, it gives you a reference to a computation that may not have completed yet.

Rewrite the async part as a Callable so that it returns a Data as a result.

Callable<Integer> task = () -> {
    Data data = new Data();
    for (int i = 0; i < 256; i++) {
        System.out.println("Data " + i + ": " + data.get(i));
    }
    return data;
};

ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Data> future = executor.submit(task);
doStuff();
// ... main thread goes about its business

// when you get to a point where you need data, 
// you can block here until the computation is done
Data data = future.get(); 

This way the Future handles making sure the Data object is made visible across threads.

Java Concurrency issues and Thread Synchronization, Learn about the common problems related to Java Concurrency like The idea of allowing a thread to acquire the same lock more than once� More sophisticated locking idioms are supported by the java.util.concurrent.locks package. We won't examine this package in detail, but instead will focus on its most basic interface, Lock. Lock objects work very much like the implicit locks used by synchronized code. As with implicit locks, only one thread can own a Lock object at a time.


I found an alternative approach to the problem which also answers my comment from the answer of @JB Nizet. ExecutorService#submit(Runnable) returns a Future<?> which can be used to wait until the task is ready. If multiple submissions should be possible one can just create a Queue<Future<?>> queue , always offer the Future<?> returned by ExecutorService#submit(Runnable) to the queue and at the point where the main thread should wait just #poll().get() the entire queue.

Edit: I have also found a related answer here: https://stackoverflow.com/a/20496115/3882565

Reading 23: Locks and Synchronization, Java actually forbids it, syntactically, because an object under construction is expected to be confined to a single thread until it has returned from its constructor. So synchronizing constructors should be unnecessary. In the Java Tutorials, read: Synchronized Methods (1 page) Java is a multi-threaded programming language which means we can develop multi-threaded program using Java. A multi-threaded program contains two or more parts that can run concurrently and each part can handle a different task at the same time making optimal use of the available resources specially when your computer has multiple CPUs.


This seems to be covered well enough by basic synchronization: doStuff expects to have sole access to the data, presumably so that it can modify the data as a whole safely. Meanwhile, doPrint expects to operation on stable data. In these two cases, the data is the unit of state to which access is controlled, and the appropriate locking technique is to synchronize on the data instance which is being accessed.

public void runningInThread1() {
    Data someData = getData(); // Obtain the data which this thread is using
    doStuff(someData); // Update the data
    // Looping and such omitted.
}

public void runningInThread2() {
    Data someData = getData();
    doPrint(someData); // Display the data
}

public void doStuff(Data data) {
    synchronized ( data ) {
        // Do some stuff to the data
    }
}

public void doPrint(Data data) {
    synchronized ( data ) {
        // Display the data
    }
}

Alternatively, if doStuff and doPrint are implemented as instance methods of Data, then the synchronization could be made to happen by adding the synchronized keyword to the instance methods.

Chapter 17. Threads and Locks, Each object in Java is associated with a monitor, which a thread can lock or or the millisecs argument is negative, then an IllegalArgumentException is thrown. What makes java application concurrent? The very first class, you will need to make a java class concurrent, is java.lang.Thread class. This class is the basis of all concurrency concepts in java. Then you have java.lang.Runnable interface to abstract the thread behavior out of thread class.


Concurrency best practices, Locks; 6. Thread Schedulers; 7. Atomic Operations; 8. Concurrent Collections; 9. the Java thread scheduler implementation details is not a great idea. has a negative impact on application performance as threads will be� overuse of java threads can be hazardous to program’s performance and its maintainability. Threads in Java. Java threads facility and API is deceptively simple: Every java program creates at least one thread [ main() thread ]. Additional threads are created through the Thread constructor or by instantiating classes that extend the Thread class.


Java Synchronization Tutorial : What, How and Why?, Synchronization in Java is an important concept since Java is a multi-threaded Java Thread acquires an object level lock when it enters into an instance and bad performance. instead of String object its advised to use new Object() for� A java.util.concurrent.locks.Lock is a thread synchronization mechanism just like synchronized blocks. A Lock is, however, more flexible and more sophisticated than a synchronized block. Since Lock is an interface, you need to use one of its implementations to use a Lock in your applications.


The "Double-Checked Locking is Broken" Declaration, Double-Checked Locking is widely cited and used as an efficient method for If this code was used in a multithreaded context, many things could go wrong. Thus, a thread which invokes getHelper() could see a non-null reference to a helper This is completely legal under the existing Java memory model, and also� 2) Thread-based Multitasking (Multithreading) Threads share the same address space. A thread is lightweight. Cost of communication between the thread is low. Note: At least one process is required for each thread. What is Thread in java. A thread is a lightweight subprocess, the smallest unit of processing. It is a separate path of execution.