Welcome to the Java Threads Introduction lesson! In this tutorial, we'll dive into the world of multi-threading in Java, a powerful feature that allows your programs to perform multiple tasks simultaneously. Let's get started! 🚀
Threads are independent paths of execution within a program. They allow the execution of multiple tasks within a single Java application. When you run a program, by default it has one thread called the main thread.
How many threads does a Java program have when it starts?
Java provides two methods for creating threads:
Thread classRunnable interfaceWe'll focus on creating threads by extending the Thread class for simplicity.
First, create a new class that extends Thread. In the class, override the run() method, where you'll write the code for the thread to execute.
public class MyThread extends Thread {
public void run() {
// Your code here
}
}To start a thread, create an instance of your thread class and call the start() method.
MyThread thread = new MyThread();
thread.start();When multiple threads access shared data, synchronization becomes crucial to prevent data inconsistencies. Java provides synchronized blocks and methods for this purpose.
public class MySyncThread extends Thread {
int count = 0;
public synchronized void increment() {
count++;
}
public void run() {
for(int i = 0; i < 1000; i++) {
increment();
}
}
}In this example, the increment() method is synchronized, ensuring that only one thread can access the count variable at a time.
Let's solve a classic problem using Java threads: the producer-consumer problem. The goal is to have two threads, one producing data (producer) and one consuming data (consumer), while ensuring that the buffer never exceeds a certain size.
class Buffer {
private int maxSize;
private int buffer[];
private int producer = 0;
private int consumer = 0;
private boolean isFull = false;
private boolean isEmpty = true;
public Buffer(int size) {
maxSize = size;
buffer = new int[maxSize];
}
public synchronized void put(int value) throws InterruptedException {
while (isFull) {
wait();
}
buffer[producer] = value;
producer = (producer + 1) % maxSize;
isFull = (producer == consumer);
if (!isEmpty) {
notify();
}
}
public synchronized int take() throws InterruptedException {
while (isEmpty) {
wait();
}
int value = buffer[consumer];
consumer = (consumer + 1) % maxSize;
isEmpty = (consumer == producer);
if (!isFull) {
notify();
}
return value;
}
}
class Producer extends Thread {
Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
public void run() {
for(int i = 0; i < 10; i++) {
try {
buffer.put(i);
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer extends Thread {
Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
public void run() {
for(int i = 0; i < 10; i++) {
try {
buffer.take();
sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}In this example, we've created a Buffer class to manage the shared data and synchronized methods for putting and taking items. The Producer and Consumer classes represent the threads that produce and consume data, respectively.
In this tutorial, we've learned the basics of creating and managing threads in Java. Multi-threading is a powerful tool that allows your programs to perform multiple tasks simultaneously, making them more responsive and efficient.
Don't forget to practice and experiment with the producer-consumer example to get a better understanding of synchronization in threads. Happy coding! 🎉
Keep learning and exploring Java's vast features at CodeYourCraft! 🌟