Tutorials Hut

Java Multithreading

Ability to execute multiple tasks at the same time in a CPU is called multithreading. Java provides a lot of classes and methods to achieve multithreading in java. A thread is a small task in a multithreaded application which can run along with other threads in parallel(almost).

  • A multithreaded code creates multiple parallel tasks which run on the CPU core at almost the same time.
  • A process is different from multi-threading, multithreading can be part of a process, for example multithreading in java runs under java process.
  • Multithreading enables you to run multiple small tasks and complete them in a concurrent and faster manner.
  • Multithreading improves efficiency and performance of application but also creates locking and other issues related to concurrency, which should be handled carefully.

Life Cycle Of Thread

There are total 5 states of a thread in java:

1. New – It is the state when we create a thread with a new key word.

2. Runnable – When we call start() method of thread, the thread goes to Runnable state which means ready to execute. Later it may get picked up, based on machine architecture and OS and moved to running state.

3. Running – In this state thread starts executing code written in run() method.

4. Waiting(sleep or wait) – When a thread is called to wait for a certain specific time is called waiting.

5. Terminated(Dead )– When thread completes the task goes to dead/terminated state.

Diagram showing states of Thread:

java_multithreading and thread state

Java Thread methods

S.N.

Modifier and Return Type

Method

Description

1)

void

start()

Starts a thread (ensures does not run in same thread)

2)

void

run()

Runs the code of thread

3)

static void

sleep()

Makes the current thread sleep for a given time.

4)

static Thread

currentThread()

Returns the current thread.

5)

void

join()

It joins two threads and 2nd waits for 1st to complete.

6)

int

getPriority()

Returns priority.

7)

void

setPriority()

Sets priority of thread.

8)

String

getName()

Returns the name of the thread.

9)

void

setName()

Sets the name of thread.

10)

long

getId()

Returns id of thread.

11)

boolean

isAlive()

Checks if the thread is alive.

12)

static void

yield()

Causes the current running thread to pause and allows another to run.

13)

void

suspend()

Suspends current thread.

14)

void

resume()

Resumes thread from suspension.

15)

void

stop()

Stop the thread.

16)

void

destroy()

It destroys thread and group of it.

17)

boolean

isDaemon()

Checks if thread is daemon.

18)

void

setDaemon()

Sets a thread to be daemon.

19)

void

interrupt()

It interrupts the thread.

20)

boolean

isinterrupted()

Checks if the thread is interrupted or not.

21)

static boolean

interrupted()

It tests whether the current thread has been interrupted.

22)

static int

activeCount()

Returns active threads count in the current thread group.

23)

void

checkAccess()

Checks if the current thread has access to modify.

24)

static boolean

holdLock()

Returns true if the current thread holds the monitor on object.

25)

static void

dumpStack()

Prints stack trace of thread.

26)

StackTraceElement[]

getStackTrace()

Returns stack trace of thread.

27)

static int

enumerate()

 

28)

Thread.State

getState()

Return state.

29)

ThreadGroup

getThreadGroup()

Returns thread group.

30)

String

toString()

Returns string of thread name, priority, group etc.

31)

void

notify()

It signals a specific thread which is waiting for an object..

32)

void

notifyAll()

It signals all threads in the waiting state of an object.

33)

void

setContextClassLoader()

Loads context class

34)

ClassLoader

getContextClassLoader()

Loads context class

35)

static Thread.UncaughtExceptionHandler

getDefaultUncaughtExceptionHandler()

Returns default exception handler.

36)

static void

setDefaultUncaughtExceptionHandler()

Sets default exception handler.

Thread Creation In Java

There are two ways to create a thread in Java.

1. By extending Thread class

2. By implementing Runnable interface and overriding run() method.

There are some differences in the above two approaches.

1. By using extend approach your class can’t extend any other class as it is already used while in case of Runnable interface your class may still extend some class.

2. Runnable approach creates an object and we pass that object to thread while in case of extending it is not so.

Example Of Java Thread Creation By Extending Thread Class

See below example of producer and consumer thread which are extending Thread class. Study it to understand.

package threads;
import java.util.Date;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class MyExtendThread extends Thread {
public static void main(String[] args) {
    BlockingDeque<String> bqueue = new LinkedBlockingDeque<String>(5);

   //Producer thread start
    Producer producer = new Producer(bqueue);
     producer.start();

    Producer producer2 = new Producer(bqueue);
    producer2.start();

    //Created Consumer thread
    Consumer consumerThread = new Consumer(bqueue);
    consumerThread.start();
    System.out.println("Main thread is dead, this does not mean other threads are dead, they still live");
}
}

class Producer extends Thread {
BlockingDeque<String> bqueue = new LinkedBlockingDeque<String>();
public Producer(BlockingDeque<String> bqueue) {
    this.bqueue = bqueue;
}

public void run() {
    while(true){
        String date = new Date().toString();
        bqueue.add(date);
        System.out.println("Producer - I have added: "+date+" in blocking queue, capacity now:"+bqueue.size()+" name"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}
class Consumer extends Thread {
BlockingDeque<String> bqueue = new LinkedBlockingDeque<String>();
public Consumer(BlockingDeque<String> bqueue) {
    this.bqueue = bqueue;
}

public void run() {
    while(true){
        String date ="";
            try {
                date = bqueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println("Consumer - I have removed: "+date+" something from blocking queue, capacity now:"+bqueue.size()+" name"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}

Output:

Main thread is dead, this does not mean other threads are dead, they still live
Producer - I have added: Wed Sep 15 18:54:35 IST 2021 in blocking queue, capacity now:0 nameThread-1
Consumer - I have removed: Wed Sep 15 18:54:35 IST 2021 something from blocking queue, capacity now:1 nameThread-2
Producer - I have added: Wed Sep 15 18:54:35 IST 2021 in blocking queue, capacity now:1 nameThread-0
Consumer - I have removed: Wed Sep 15 18:54:35 IST 2021 something from blocking queue, capacity now:0 nameThread-2
Producer - I have added: Wed Sep 15 18:54:36 IST 2021 in blocking queue, capacity now:2 nameThread-0
Producer - I have added: Wed Sep 15 18:54:36 IST 2021 in blocking queue, capacity now:1 nameThread-1
Consumer - I have removed: Wed Sep 15 18:54:36 IST 2021 something from blocking queue, capacity now:1 nameThread-2
Producer - I have added: Wed Sep 15 18:54:37 IST 2021 in blocking queue, capacity now:3 nameThread-1
Producer - I have added: Wed Sep 15 18:54:37 IST 2021 in blocking queue, capacity now:3 nameThread-0

Example of Java Thread Creation By Implementing Runnable Interface

package threads;
import java.util.Date;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

class MyRunnableThread extends Thread {
public static void main(String[] args) {

    BlockingDeque<String> bqueue = new LinkedBlockingDeque<String>(5);
    //Producer thread start
    ProducerRunnable producer = new ProducerRunnable(bqueue);
    new Thread(producer).start();

Producer producer2 = new Producer(bqueue);
     producer2.start();

    //Created Consumer thread
    ConsumerRunnable consumerThread = new ConsumerRunnable(bqueue);
    new Thread(consumerThread).start();
    System.out.println("Main thread is dead, this does not mean other threads are dead, they will still live");
}
}
class ProducerRunnable implements Runnable {
BlockingDeque<String> bqueue;

public ProducerRunnable(BlockingDeque<String> bqueue) {
    this.bqueue = bqueue;
}

public void run() {
    while(true){
        String date = new Date().toString();
        bqueue.add(date);
        System.out.println("Producer - I have added: "+date+" in blocking queue, capacity now:"+bqueue.size()+" name"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}

class ConsumerRunnable implements Runnable {
BlockingDeque<String> bqueue;
public ConsumerRunnable(BlockingDeque<String> bqueue) {
    this.bqueue = bqueue;
}

public void run() {
    while(true){
        String date ="";
        try {
            date = bqueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
         }

        System.out.println("Consumer - I have removed: "+date+" something from blocking queue, capacity now:"+bqueue.size()+" name"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}

Output

Main thread is dead, this does not mean other threads are dead, they will still live
Producer - I have added: Thu Sep 16 10:18:27 IST 2021 in blocking queue, capacity now:0 nameThread-0
Consumer - I have removed: Thu Sep 16 10:18:27 IST 2021 something from blocking queue, capacity now:1 nameThread-2
Producer - I have added: Thu Sep 16 10:18:27 IST 2021 in blocking queue, capacity now:1 nameThread-1
Consumer - I have removed: Thu Sep 16 10:18:27 IST 2021 something from blocking queue, capacity now:0 nameThread-2
Producer - I have added: Thu Sep 16 10:18:28 IST 2021 in blocking queue, capacity now:2 nameThread-0
Producer - I have added: Thu Sep 16 10:18:28 IST 2021 in blocking queue, capacity now:1 nameThread-1
Consumer - I have removed: Thu Sep 16 10:18:28 IST 2021 something from blocking queue, capacity now:1 nameThread-2
Producer - I have added: Thu Sep 16 10:18:29 IST 2021 in blocking queue, capacity now:3 nameThread-0
Producer - I have added: Thu Sep 16 10:18:29 IST 2021 in blocking queue, capacity now:2 nameThread-1
Consumer - I have removed: Thu Sep 16 10:18:28 IST 2021 something from blocking queue, capacity now:2 nameThread

Example of Thread Creation Using Functional Interface and Lambda Expression

package threads;
public class LambdaExpressionThreads {
public static void main(String[] args) {

    //Using functional interface concept
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("I am a thread, created without lambda with functional interface.");
        }
    }).start();

    //Lamda expression to create thread, same as above but with lamda
    new Thread(() -> {
        System.out.println("I am a thread, created with lambda expression.");
    }).start();
}
}

Output

I am a thread, created without lambda with a functional interface.
I am a thread, created with lambda expressions.

Next Article


















  • Leave a Reply

    Your email address will not be published. Required fields are marked *