During reading Thread documentation I found a class that existence I've ignored until now - LockSupport. Some of its methods influence Thread states, so it was quite natural choice for the topic of next posts.
Data Engineering Design Patterns

Looking for a book that defines and solves most common data engineering problems? I wrote
one on that topic! You can read it online
on the O'Reilly platform,
or get a print copy on Amazon.
I also help solve your data engineering problems 👉 contact@waitingforcode.com 📩
As told, this post presents LockSupport. The first part explains its role and the API. The second part shows the use of LockSupport through several test cases.
LockSupport presentation
LockSupport is a class located in java.util.concurrent.locks package. Its neighbours are the classes and interfaces as: Lock, ReentrantLock or ReentrantWriteLock. Thanks to this neighbourhood it can be easily deduced that LockSupports is a kind of lock mechanism. The Javadoc confirms that by defining LockSupport as:
Basic thread blocking primitives for creating locks and other synchronization classes.
More specifically, LockSupport provides an alternative for some of Thread's deprecated methods: suspend() and resume(). It uses a concept of permit and parking to detect if given thread should block or not. Permit is associated to each class using LockSupport and is manipulated through park-like methods as:
- park() - blocks the execution of the current thread.
- time-based park - a thread can also be "parked" within specified delay: during some time (parkNanos(long)) or until some time (parkUntil(long))
- park with blocker - park methods allow to pass an object called blocker: (park(Object), parkNanos(Object, long), parkUntil(Object, long)). The blocker is assigned to blocked thread. But beware, it's not a kind of exclusive lock. More than that, the blocker is assigned to thread even before stopping it:
public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, 0L); setBlocker(t, null); }
Only with some extra work it could be used as for example a lock. It's shown in one of examples from the next part. - unpark(Thread) - unblocks given Thread, i.e. the permit is made available again.
LockSupport example
Following examples show the utility of LockSupport:
@Test public void should_unblock_parked_thread() throws InterruptedException { List<Integer> iteratedNumbers = new ArrayList<>(); Thread thread1 = new Thread(() -> { int i = 0; // park() blocks thread invoking this method LockSupport.park(); while (true) { try { Thread.sleep(1_000L); iteratedNumbers.add(i); i++; } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } }); thread1.start(); Thread thread2 = new Thread(() -> { try { Thread.sleep(2_600L); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } // unpark(Thread) releases thread specified // in the parameter LockSupport.unpark(thread1); }); thread2.start(); Thread.sleep(5_000L); thread1.interrupt(); assertThat(iteratedNumbers).hasSize(2); // Only 2 numbers are expected: // * thread1 blocks before starting the iteration // * thread2 wakes up after ~3 seconds and releases blocked thread1 // * from 5 seconds allocated to execution, thread1 has only 2 // seconds to execute and since the sleep between iterations // is 1 second, it should make only 2 iterations assertThat(iteratedNumbers).containsOnly(0, 1); } @Test public void should_block_thread_with_deadline() throws InterruptedException { List<Integer> iteratedNumbers = new ArrayList<>(); Thread thread1 = new Thread(() -> { int i = 0; // park() blocks thread invoking this method long lockReleaseTimestamp = System.currentTimeMillis()+2_600L; LockSupport.parkUntil(lockReleaseTimestamp); while (true) { try { Thread.sleep(1_000L); iteratedNumbers.add(i); i++; } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } }); thread1.start(); Thread.sleep(5_000L); thread1.interrupt(); assertThat(iteratedNumbers).hasSize(2); // Only 2 numbers are expected because lock is held during ~3 seconds: // * thread1 blocks before starting the iteration during ~3 seconds // * from 5 seconds allocated to execution, thread1 has only 2 seconds // of execution time and since the sleep between iterations is 1 second, // it should make only 2 iterations assertThat(iteratedNumbers).containsOnly(0, 1); } @Test public void should_prove_that_blocker_is_not_an_exclusive_lock() throws InterruptedException { Object lock = new Object(); boolean[] blocks = new boolean[2]; Thread thread1 = new Thread(() -> { LockSupport.park(lock); blocks[0] = true; }); thread1.start(); Thread thread2 = new Thread(() -> { LockSupport.park(lock); blocks[1] = true; }); thread2.start(); Thread.sleep(2_000L); // Both threads stopped with the same blocker object (Object lock) // It shows that blocker can't work as an exclusive lock mechanism Object blockerThread1 = LockSupport.getBlocker(thread1); Object blockerThread2 = LockSupport.getBlocker(thread2); assertThat(blockerThread1).isEqualTo(lock); assertThat(blockerThread2).isEqualTo(lock); assertThat(blocks[0]).isFalse(); assertThat(blocks[1]).isFalse(); } @Test public void should_implement_locking_mechanism_with_blocker() throws InterruptedException { Object lock = new Object(); Thread thread1 = new Thread(() -> { LockSupport.parkUntil(lock, System.currentTimeMillis()+3_000L); }); thread1.start(); long timeBeforeLockAcquire = System.currentTimeMillis(); // Give some guarantee to thread1 to acquire lock Thread.sleep(10L); // Try to lock current thread as long as // thread1 doesn't release its lock - let's suppose // that thread1 is making some job needed by current thread while (LockSupport.getBlocker(thread1) != null) { } LockSupport.parkUntil(lock, System.currentTimeMillis()+1_000L); long timeAfterLockRelease = System.currentTimeMillis(); long duration = timeAfterLockRelease - timeBeforeLockAcquire; // Duration should be ~4 seconds because of 3 seconds of lock // acquired by thread1 and 1-second blocking of current thread assertThat(duration).isEqualTo(4_000L); }
This post shows LockSupport. It's one of solutions to suspend and resume threads in Java. It represents this concept by the abstraction of parking/unparking which means making a permit available/unavailable (resume/suspend thread). It contains simple parking methods and also time-based. LockSupport makes also possible the use of blocker object which with a some of additional logic can be used as lock.
Consulting

With nearly 16 years of experience, including 8 as data engineer, I offer expert consulting to design and optimize scalable data solutions.
As an O’Reilly author, Data+AI Summit speaker, and blogger, I bring cutting-edge insights to modernize infrastructure, build robust pipelines, and
drive data-driven decision-making. Let's transform your data challenges into opportunities—reach out to elevate your data engineering game today!
👉 contact@waitingforcode.com
đź”— past projects