Java is a popular programming language that is widely used for developing various applications. One of the key features of Java is its support for multithreading. Multithreading is the ability of a program to execute multiple threads of execution simultaneously. Java threads are lightweight processes that can run concurrently with other threads in a Java program.
Java threads are objects that are created and managed by the Java Virtual Machine (JVM). Each thread has its own call stack, which is used to store the state of the thread. Threads can communicate with each other by sharing data or by sending messages. Java threads are used to perform tasks that can be executed independently of the main program. For example, a Java program that downloads files from the internet can use multiple threads to download files simultaneously, which can significantly improve the performance of the program.
Java threads are created by extending the Thread class or by implementing the Runnable interface. The Thread class provides several methods that can be used to control the behavior of a thread, such as start(), sleep(), and join(). The Runnable interface defines a single method, run(), which is used to define the behavior of a thread.
Here are some examples of Java threads:
class MyThread extends Thread {
public void run() {
System.out.println("Hello from MyThread!");
}
}
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}
In this example, we create a new thread by extending the Thread class and overriding its run() method. We then create an instance of the MyThread class and call its start() method to start the thread. When the thread starts running, it will execute the code in the run() method, which simply prints a message to the console.
class MyRunnable implements Runnable {
public void run() {
System.out.println("Hello from MyRunnable!");
}
}
public class Main {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
}
}
In this example, we create a new thread by implementing the Runnable interface and defining its run() method. We then create an instance of the MyRunnable class and pass it to the constructor of a new Thread object. We then call the start() method of the Thread object to start the thread. When the thread starts running, it will execute the code in the run() method, which simply prints a message to the console.
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
class MyThread extends Thread {
private Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
MyThread t1 = new MyThread(counter);
MyThread t2 = new MyThread(counter);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + counter.getCount());
}
}
In this example, we create a Counter class that has two synchronized methods: increment() and getCount(). We then create two instances of the MyThread class, passing the same Counter object to both threads. Each thread increments the counter 1000 times. We then wait for both threads to finish using the join() method and print the final value of the counter. Because the increment() and getCount() methods are synchronized, the counter is incremented correctly even though two threads are accessing it simultaneously.