codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
☕

Java Programming

59 / 65 topics
56Java Wrapper Classes57Java Generics58Java RegEx59Java Threads60Java Lambda
Tutorials/Java Programming/Java Threads
☕Java Programming

Java Threads

Updated 2026-05-12
30 min read

Java Threads

In this tutorial, we will explore the concept of threads in Java, which are essential for building responsive and efficient applications. Understanding how to create and manage threads is crucial for developing multi-threaded applications that can handle multiple tasks concurrently.

Introduction

Threads allow a program to execute multiple operations simultaneously. In Java, you can create threads by either extending the Thread class or implementing the Runnable interface. Each approach has its own use cases and advantages, which we will discuss in detail. Additionally, managing concurrency issues is vital to ensure that threads do not interfere with each other, leading to unexpected behavior.

Extending Thread vs Implementing Runnable

Extending Thread

When you extend the Thread class, your class becomes a thread itself. This approach is straightforward but has limitations because Java does not support multiple inheritance. Therefore, if your class needs to extend another class, implementing the Runnable interface is a better choice.

Example: Extending Thread

Java
1class MyThread extends Thread {
2 public void run() {
3 for (int i = 1; i <= 5; i++) {
4 System.out.println("Thread " + Thread.currentThread().getId() + ": " + i);
5 };
6 }
7
8 public static void main(String[] args) {
9 MyThread thread1 = new MyThread();
10 thread1.start();
11
12 for (int i = 1; i <= 5; i++) {
13 System.out.println("Main Thread: " + i);
14 }
15 }
16}
Output
Thread 10: 1
Main Thread: 1
Thread 10: 2
Main Thread: 2
Thread 10: 3
Main Thread: 3
Thread 10: 4
Main Thread: 4
Thread 10: 5
Main Thread: 5

Implementing Runnable

Implementing the Runnable interface allows your class to define a task that can be executed by a thread. This approach is more flexible as it separates the task from the thread management, making it easier to share tasks among multiple threads.

Example: Implementing Runnable

Java
1class MyTask implements Runnable {
2 public void run() {
3 for (int i = 1; i <= 5; i++) {
4 System.out.println("Thread " + Thread.currentThread().getId() + ": " + i);
5 }
6 }
7
8 public static void main(String[] args) {
9 MyTask task = new MyTask();
10 Thread thread1 = new Thread(task);
11 thread1.start();
12
13 for (int i = 1; i <= 5; i++) {
14 System.out.println("Main Thread: " + i);
15 }
16 }
17}
Output
Thread 10: 1
Main Thread: 1
Thread 10: 2
Main Thread: 2
Thread 10: 3
Main Thread: 3
Thread 10: 4
Main Thread: 4
Thread 10: 5
Main Thread: 5

Concurrency Problems

Concurrency issues arise when multiple threads access shared resources simultaneously. Common problems include race conditions, deadlocks, and livelocks.

Race Conditions

A race condition occurs when the outcome of a program depends on the sequence or timing of uncontrollable events such as thread scheduling. This can lead to inconsistent results.

Example: Race Condition

Java
1class Counter {
2 private int count = 0;
3
4 public void increment() {
5 count++;
6 }
7
8 public int getCount() {
9 return count;
10 }
11}
12
13class MyThread extends Thread {
14 private Counter counter;
15
16 public MyThread(Counter counter) {
17 this.counter = counter;
18 }
19
20 public void run() {
21 for (int i = 0; i < 1000; i++) {
22 counter.increment();
23 }
24 }
25
26 public static void main(String[] args) throws InterruptedException {
27 Counter counter = new Counter();
28 MyThread thread1 = new MyThread(counter);
29 MyThread thread2 = new MyThread(counter);
30
31 thread1.start();
32 thread2.start();
33
34 thread1.join();
35 thread2.join();
36
37 System.out.println("Final Count: " + counter.getCount());
38 }
39}
Output
Final Count: 1950

Deadlocks

A deadlock occurs when two or more threads are blocked forever, waiting for each other. This typically happens when threads hold locks on resources and try to acquire additional locks held by other threads.

Example: Deadlock

Java
1class Resource {
2 public synchronized void method1(Resource other) {
3 System.out.println("Thread " + Thread.currentThread().getId() + " in method1");
4 other.method2(this);
5 }
6
7 public synchronized void method2(Resource other) {
8 System.out.println("Thread " + Thread.currentThread().getId() + " in method2");
9 }
10}
11
12class MyThread extends Thread {
13 private Resource resource1;
14 private Resource resource2;
15
16 public MyThread(Resource resource1, Resource resource2) {
17 this.resource1 = resource1;
18 this.resource2 = resource2;
19 }
20
21 public void run() {
22 resource1.method1(resource2);
23 }
24
25 public static void main(String[] args) {
26 Resource resource1 = new Resource();
27 Resource resource2 = new Resource();
28
29 MyThread thread1 = new MyThread(resource1, resource2);
30 MyThread thread2 = new MyThread(resource2, resource1);
31
32 thread1.start();
33 thread2.start();
34 }
35}
Output
Thread 10 in method1
Thread 11 in method1

Livelocks

A livelock occurs when two or more threads keep changing their state in response to each other without making any progress. This is similar to a deadlock but involves active thread behavior.

Example: Livelock

Java
1class Task {
2 private boolean flag = true;
3
4 public synchronized void setFlag(boolean flag) {
5 this.flag = flag;
6 }
7
8 public synchronized boolean getFlag() {
9 return flag;
10 }
11}
12
13class MyThread extends Thread {
14 private Task task;
15
16 public MyThread(Task task) {
17 this.task = task;
18 }
19
20 public void run() {
21 while (true) {
22 if (task.getFlag()) {
23 System.out.println("Thread " + Thread.currentThread().getId() + " is running");
24 try {
25 sleep(100);
26 } catch (InterruptedException e) {
27 e.printStackTrace();
28 }
29 task.setFlag(false);
30 }
31 }
32 }
33
34 public static void main(String[] args) {
35 Task task = new Task();
36 MyThread thread1 = new MyThread(task);
37 MyThread thread2 = new MyThread(task);
38
39 thread1.start();
40 thread2.start();
41 }
42}
Output
Thread 10 is running
Thread 11 is running
Thread 10 is running
Thread 11 is running

Checking Thread Status

The isAlive() method of the Thread class can be used to check if a thread is still running.

Example: Using isAlive()

Java
1class MyThread extends Thread {
2 public void run() {
3 for (int i = 1; i <= 5; i++) {
4 System.out.println("Thread " + Thread.currentThread().getId() + ": " + i);
5 try {
6 sleep(100);
7 } catch (InterruptedException e) {
8 e.printStackTrace();
9 }
10 }
11 }
12
13 public static void main(String[] args) throws InterruptedException {
14 MyThread thread = new MyThread();
15 thread.start();
16
17 while (thread.isAlive()) {
18 System.out.println("Main Thread: " + thread.isAlive());
19 sleep(200);
20 }
21
22 System.out.println("Main Thread: " + thread.isAlive());
23 }
24}
Output
Main Thread: true
Thread 10: 1
Main Thread: true
Thread 10: 2
Main Thread: true
Thread 10: 3
Main Thread: true
Thread 10: 4
Main Thread: true
Thread 10: 5
Main Thread: false

Practical Example

Let's create a simple application that simulates a bank account with concurrent deposits and withdrawals.

Java
1class BankAccount {
2 private int balance = 0;
3
4 public synchronized void deposit(int amount) {
5 balance += amount;
6 System.out.println("Deposited " + amount);
7 }
8
9 public synchronized void withdraw(int amount) {
10 if (balance >= amount) {
11 balance -= amount;
12 System.out.println("Withdrew " + amount);
13 } else {
14 System.out.println("Insufficient funds");
15 }
16 }
17
18 public int getBalance() {
19 return balance;
20 }
21}
22
23class DepositTask implements Runnable {
24 private BankAccount account;
25 private int amount;
26
27 public DepositTask(BankAccount account, int amount) {
28 this.account = account;
29 this.amount = amount;
30 }
31
32 public void run() {
33 for (int i = 0; i < 5; i++) {
34 account.deposit(amount);
35 }
36 }
37}
38
39class WithdrawTask implements Runnable {
40 private BankAccount account;
41 private int amount;
42
43 public WithdrawTask(BankAccount account, int amount) {
44 this.account = account;
45 this.amount = amount;
46 }
47
48 public void run() {
49 for (int i = 0; i < 5; i++) {
50 account.withdraw(amount);
51 }
52 }
53}
54
55public class BankApp {
56 public static void main(String[] args) throws InterruptedException {
57 BankAccount account = new BankAccount();
58
59 DepositTask depositTask = new DepositTask(account, 100);
60 WithdrawTask withdrawTask = new WithdrawTask(account, 50);
61
62 Thread depositThread = new Thread(depositTask);
63 Thread withdrawThread = new Thread(withdrawTask);
64
65 depositThread.start();
66 withdrawThread.start();
67
68 depositThread.join();
69 withdrawThread.join();
70
71 System.out.println("Final Balance: " + account.getBalance());
72 }
73}
Output
Deposited 100
Withdrew 50
Deposited 100
Withdrew 50
Deposited 100
Withdrew 50
Deposited 100
Withdrew 50
Deposited 100
Withdrew 50
Final Balance: 250

Summary

  • Extending Thread vs Implementing Runnable: Extending Thread is straightforward but limits inheritance. Implementing Runnable provides more flexibility and is generally preferred.
  • Concurrency Problems: Be aware of race conditions, deadlocks, and livelocks to ensure thread safety.
  • Checking Thread Status: Use isAlive() to check if a thread is still running.

What's Next?

In the next tutorial, we will explore Java Lambdas. Lambdas provide a concise way to represent one-method interfaces (functional interfaces) and are integral to modern Java programming. This will help you write more functional-style code and take full advantage of Java 8 and later features. Stay tuned!


PreviousJava RegExNext Java Lambda

Recommended Gear

Java RegExJava Lambda