Java Multithreading Basics: History, Thread States, Creation Methods, Synchronization, and Control
This article provides a comprehensive introduction to Java multithreading, covering its historical background, thread lifecycle states, two ways to create threads, code examples for shared and non‑shared data, synchronization with the synchronized keyword, thread control methods such as interrupt, sleep, suspend, yield, priority settings, and daemon threads, concluding with key takeaways.
The series introduces Java multithreading from scratch, referencing classic books and aiming to simplify complex concepts.
Concurrency History
Before operating systems, a computer could run only one program, leading to resource waste.
Operating systems were introduced to improve resource utilization, fairness, and convenience, which also gave rise to threads that can share process resources.
Thread Advantages
Modern multi‑processor systems benefit from multiple threads; using a single thread on a dual‑processor wastes resources.
Thread States
New: created but not started.
Runnable (Running/Ready): may be executing or waiting for a CPU time slice.
Waiting: waiting to be explicitly awakened (e.g., wait, join, LockSupport.park).
Timed Waiting: automatically awakened after a timeout.
Blocked: waiting to acquire an exclusive lock.
Terminated: execution finished.
Two Ways to Create Threads
Extend Thread
Implement Runnable interface
Extending Thread
Code execution order is independent of code order:
public class T1 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println("代码的执行结果与代码的顺序无关");
}
}
class MyThread extends Thread {
public void run() {
System.out.println("创建的线程");
}
}Calling run() directly executes synchronously in the main thread, while start() lets the JVM schedule the run() method in a new thread.
public class T1 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.run();
System.out.println("如果是直接执行run方法,肯定是按代码顺序执行的,因为是通过主线程调用的");
}
}
class MyThread extends Thread {
public void run() {
System.out.println("创建的线程");
}
}Implementing Runnable
Preferred when the class already has a superclass because Java does not support multiple inheritance.
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("运行中!");
}
}
public class Run {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
System.out.println("运行结束!");
}
}Thread Data Non‑Sharing
public static void main(String[] args) {
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
MyThread c = new MyThread("C");
a.start();
b.start();
c.start();
}
class MyThread extends Thread {
private int count = 5;
public MyThread(String name) {
super();
this.setName(name);
}
@Override
public void run() {
super.run();
while (count > 0) {
count--;
System.out.println("由 " + this.currentThread().getName() + " 计算,count=" + count);
}
}
}Each thread maintains its own count variable, so the value is not shared.
Thread Data Sharing
public static void main(String[] args) {
MyThread mythread = new MyThread();
Thread a = new Thread(mythread, "A");
Thread b = new Thread(mythread, "B");
Thread c = new Thread(mythread, "C");
a.start();
b.start();
c.start();
}All three threads run the same MyThread instance, so they share the same data; the non‑atomic i++ can cause duplicate outputs.
Synchronized Keyword
public synchronized void run() {
super.run();
count--;
System.out.println("由 " + this.currentThread().getName() + " 计算,count=" + count);
}The synchronized method acquires a lock, ensuring that only one thread executes the critical section at a time.
Thread Methods
currentThread() : obtain the current thread.
isAlive() : check if a thread has been started and not yet terminated.
sleep() : pause the thread.
getId() : get the thread’s unique identifier.
suspend() , resume() , stop() : deprecated and unsafe.
Stopping a Thread
Thread ends automatically after run() finishes.
stop() forces termination (unsafe).
interrupt() sets an interrupt flag without immediately stopping execution.
interrupt Method
The interrupt flag is set to true; the thread must cooperate to stop.
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
System.out.println("i=" + (i + 1));
}
}
}Even after interrupting, the loop continues because the code does not check the flag.
Checking Interrupt Status
interrupted() : checks the current thread’s interrupt status and clears the flag.
isInterrupted() : checks the target thread’s status without clearing it.
public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(1000);
thread.interrupt();
System.out.println("是否停止1?=" + thread.interrupted()); // false, checks main thread
System.out.println("是否停止2?=" + thread.interrupted()); // false
} catch (InterruptedException e) { }
}
}
public class Run2 {
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println("是否停止1?=" + Thread.interrupted()); // true
System.out.println("是否停止2?=" + Thread.interrupted()); // false
}
}Interrupt‑Driven Stop
Inside run() , periodically check isInterrupted() and break or throw an exception.
public class MyThread extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("已经是停止状态了!我要退出了!");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
} catch (InterruptedException e) {
System.out.println("进MyThread.run方法中的catch了!");
e.printStackTrace();
}
}
}Return‑Based Stop
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("已经是停止状态了!我要退出了!");
return;
}
System.out.println("i=" + (i + 1));
}sleep and interrupt
If a thread is sleeping and receives an interrupt, an InterruptedException is thrown.
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
class MyThread extends Thread {
@Override
public void run() {
try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止!进入catch!" + this.isInterrupted());
e.printStackTrace();
}
}
}Suspend (Deprecated)
The deprecated suspend() method can lock a monitor indefinitely, causing deadlocks.
public static void main(String[] args) {
final SynchronizedObject object = new SynchronizedObject();
Thread thread1 = new Thread() {
public void run() { object.printString(); }
};
thread1.setName("a");
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread() {
public void run() {
System.out.println("thread2启动了,但进入不了printString()方法!只打印1个begin");
object.printString();
}
};
thread2.start();
}
class SynchronizedObject {
synchronized public void printString() {
System.out.println("begin");
if (Thread.currentThread().getName().equals("a")) {
System.out.println("a线程永远 suspend了!");
Thread.currentThread().suspend();
}
System.out.println("end");
}
}yield Method
yield() hints to the scheduler that the current thread is willing to pause and let other threads run, though the exact timing is unspecified.
Thread Priority
Higher‑priority threads are more likely to receive CPU time; priority can be set with setPriority() . Priority is inherited by child threads.
public static void main(String[] args) {
System.out.println("main thread begin priority=" + Thread.currentThread().getPriority());
Thread.currentThread().setPriority(6);
System.out.println("main thread end priority=" + Thread.currentThread().getPriority());
MyThread1 thread1 = new MyThread1();
thread1.start();
}
class MyThread1 extends Thread {
public void run() {
System.out.println("MyThread1 run priority=" + this.getPriority());
MyThread2 thread2 = new MyThread2();
thread2.start();
}
}Daemon Threads
Daemon threads (e.g., garbage‑collector thread) run in the background and terminate automatically when all user threads finish.
Summary
Threads improve resource utilization.
Threads can be created by extending Thread or implementing Runnable .
Interrupting a thread sets a flag; actual termination must be handled in run() via checks, exceptions, or returns.
interrupted() clears the flag; isInterrupted() does not.
Sleep throws InterruptedException when the thread is interrupted.
Deprecated methods like suspend() can cause deadlocks.
Thread priority influences CPU scheduling but does not guarantee order.
Daemon threads live only while user threads exist.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.