Fundamentals 11 min read

Understanding Processes, Threads, Multithreading, and Thread Safety in Java

This article explains the fundamentals of processes, threads, and multithreading in Java, illustrates common thread‑safety problems with example code, and demonstrates how to achieve safe concurrent execution using synchronized blocks and the Lock API, including tryLock with timeout.

Java Captain
Java Captain
Java Captain
Understanding Processes, Threads, Multithreading, and Thread Safety in Java

We often talk about thread safety, but many developers lack a clear understanding of what it truly means; this article explains the concepts of processes, threads, multithreading, and thread safety in Java.

First, a process is an independent program instance; examples include QQ, music players, and system utilities. A thread is the smallest execution unit within a process, and each process contains at least one thread.

Multithreading introduces the notions of serial and parallel execution. Serial execution runs tasks one after another, while parallel execution runs multiple tasks simultaneously, as illustrated by file‑download examples.

Thread safety concerns arise when multiple threads access shared mutable state. The article shows a simple Java method that increments a counter and prints it, demonstrating that concurrent execution can produce duplicate values, indicating a lack of thread safety.

Example of a non‑thread‑safe method:

Integer count = 0;

public void getCount() {
    count ++;
    System.out.println(count);
}

To achieve thread safety, the article introduces the synchronized keyword, explaining that it locks the object (or class) and that non‑static synchronized methods lock the instance (this). Proper use of synchronized avoids race conditions but should be limited to avoid performance penalties.

Example using synchronized:

public class ThreadDemo {
    int count = 0; // record method hit count
    public synchronized void threadMethod(int j) {
        count++;
        int i = 1;
        j = j + i;
    }
}

The article then presents the Lock interface (e.g., ReentrantLock) which offers explicit lock acquisition and release, the ability to interrupt waiting threads, and the tryLock() method that returns immediately with a boolean result.

Example of using Lock with try‑finally:

private Lock lock = new ReentrantLock(); // ReentrantLock is a subclass of Lock

private void method(Thread thread) {
    lock.lock(); // acquire lock
    try {
        System.out.println("线程名:" + thread.getName() + "获得了锁");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        System.out.println("线程名:" + thread.getName() + "释放了锁");
        lock.unlock(); // release lock
    }
}

Example main method that starts two threads:

public static void main(String[] args) {
    LockTest lockTest = new LockTest();
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            lockTest.method(Thread.currentThread());
        }
    }, "t1");
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            lockTest.method(Thread.currentThread());
        }
    }, "t2");
    t1.start();
    t2.start();
}

The tryLock() method behaves differently: if the lock is unavailable it returns false immediately, avoiding indefinite waiting.

Example of tryLock() without timeout:

if (lock.tryLock()) {
    try {
        System.out.println("线程名:" + thread.getName() + "获得了锁");
    } finally {
        System.out.println("线程名:" + thread.getName() + "释放了锁");
        lock.unlock();
    }
}

A timed version can limit the waiting period. The article shows tryLock(2, TimeUnit.SECONDS) and tryLock(5, TimeUnit.SECONDS) to wait up to 2 or 5 seconds before giving up.

Example of timed tryLock (2 seconds):

if (lock.tryLock(2, TimeUnit.SECONDS)) {
    try {
        System.out.println("线程名:" + thread.getName() + "获得了锁");
        Thread.sleep(3000); // simulate long task
    } finally {
        System.out.println("线程名:" + thread.getName() + "释放了锁");
        lock.unlock();
    }
}

When the waiting time is increased to 5 seconds, the second thread can acquire the lock after the first thread releases it, as demonstrated by the output screenshots.

Overall, the article demonstrates practical ways to make Java code thread‑safe using synchronized blocks and the Lock API, and encourages readers to like and share the content.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javathread safetymultithreadingLocksynchronized
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.