[Go to site: main page, start]

0% found this document useful (0 votes)
16 views6 pages

Java Multi-threading Examples

The document contains 3 Java programs that use multiple threads: 1. A program that creates 2 threads to find and print even and odd numbers from 1 to 20 using synchronization and wait/notify. 2. A program that sorts an array of integers using multiple threads, each thread sorting a segment of the array, followed by a merge sort. 3. A program that performs matrix multiplication using multiple threads, each thread calculating a segment of the result matrix.

Uploaded by

Krishanu Naskar
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views6 pages

Java Multi-threading Examples

The document contains 3 Java programs that use multiple threads: 1. A program that creates 2 threads to find and print even and odd numbers from 1 to 20 using synchronization and wait/notify. 2. A program that sorts an array of integers using multiple threads, each thread sorting a segment of the array, followed by a merge sort. 3. A program that performs matrix multiplication using multiple threads, each thread calculating a segment of the result matrix.

Uploaded by

Krishanu Naskar
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Write a Java program that creates two threads to find and print even and odd numbers from 1 to 20

public class Find_Even_Odd_Number {


private static final int MAX_NUMBER = 20;
private static Object lock = new Object();
private static boolean isEvenTurn = true;

public static void main(String[] args) {


Thread evenThread = new Thread(() -> {
for (int i = 2; i <= MAX_NUMBER; i += 2) {
synchronized(lock) {
while (!isEvenTurn) {
try {
[Link]();
} catch (InterruptedException e) {
[Link]();
}
}
[Link]("Even Number from evenThread: " + i);
isEvenTurn = false;
[Link]();
}
}
});

Thread oddThread = new Thread(() -> {


for (int i = 1; i <= MAX_NUMBER; i += 2) {
synchronized(lock) {
while (isEvenTurn) {
try {
[Link]();
} catch (InterruptedException e) {
[Link]();
}
}
[Link]("Odd Number from oddThread: " + i);
isEvenTurn = true;
[Link]();
}
}
});

[Link]();
[Link]();
}
}
Write a Java program that sorts an array of integers using multiple threads

import [Link];

public class ParallelSort {


private static final int ARRAY_SIZE = 400;
private static final int NUM_THREADS = 4;

public static void main(String[] args) {


int[] array = createArray();
[Link]("Before sorting: " + [Link](array));

Thread[] threads = new Thread[NUM_THREADS];


int segmentSize = ARRAY_SIZE / NUM_THREADS;

for (int i = 0; i < NUM_THREADS; i++) {


int startIndex = i * segmentSize;
int endIndex = (i == NUM_THREADS - 1) ? ARRAY_SIZE - 1 : (startIndex + segmentSize - 1);
threads[i] = new Thread(new SortTask(array, startIndex, endIndex));
threads[i].start();
}

for (Thread thread: threads) {


try {
[Link]();
} catch (InterruptedException e) {
[Link]();
}
}

mergeSort(array, 0, ARRAY_SIZE - 1);

[Link]("After sorting: " + [Link](array));


}

private static int[] createArray() {


int[] array = new int[ARRAY_SIZE];
for (int i = 0; i < ARRAY_SIZE; i++) {
array[i] = (int)([Link]() * 400); // Generate random numbers between 0 and 400
}
return array;
}

private static void mergeSort(int[] array, int left, int right) {


if (left < right) {
int mid = (left + right) / 2;
mergeSort(array, left, mid);
mergeSort(array, mid + 1, right);
merge(array, left, mid, right);
}
}

private static void merge(int[] array, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int i = left, j = mid + 1, k = 0;

while (i <= mid && j <= right) {


if (array[i] <= array[j]) {
temp[k++] = array[i++];
} else {
temp[k++] = array[j++];
}
}

while (i <= mid) {


temp[k++] = array[i++];
}

while (j <= right) {


temp[k++] = array[j++];
}

[Link](temp, 0, array, left, [Link]);


}

static class SortTask implements Runnable {


private int[] array;
private int startIndex;
private int endIndex;

public SortTask(int[] array, int startIndex, int endIndex) {


[Link] = array;
[Link] = startIndex;
[Link] = endIndex;
}

@Override
public void run() {
[Link](array, startIndex, endIndex + 1);
}
}
}
Write a Java program that performs matrix multiplication using multiple threads.

public class MatrixMultiplication {


private static final int MATRIX_SIZE = 3;
private static final int NUM_THREADS = 2;

public static void main(String[] args) {


int[][] matrix1 = {
{
1,
2,
3
},
{
4,
5,
6
},
{
7,
8,
9
}
};

int[][] matrix2 = {
{
9,
8,
7
},
{
6,
5,
4
},
{
3,
2,
1
}
};

int[][] result = new int[MATRIX_SIZE][MATRIX_SIZE];

Thread[] threads = new Thread[NUM_THREADS];


int segmentSize = MATRIX_SIZE / NUM_THREADS;
for (int i = 0; i < NUM_THREADS; i++) {
int startIndex = i * segmentSize;
int endIndex = (i == NUM_THREADS - 1) ? MATRIX_SIZE - 1 : (startIndex + segmentSize - 1);
threads[i] = new Thread(new MultiplicationTask(matrix1, matrix2, result, startIndex, endIndex));
threads[i].start();
}

for (Thread thread: threads) {


try {
[Link]();
} catch (InterruptedException e) {
[Link]();
}
}

// Print the result matrix


[Link]("Result:");
for (int[] row: result) {
for (int element: row) {
[Link](element + " ");
}
[Link]();
}
}

static class MultiplicationTask implements Runnable {


private int[][] matrix1;
private int[][] matrix2;
private int[][] result;
private int startIndex;
private int endIndex;

public MultiplicationTask(int[][] matrix1, int[][] matrix2, int[][] result, int startIndex, int endIndex) {
this.matrix1 = matrix1;
this.matrix2 = matrix2;
[Link] = result;
[Link] = startIndex;
[Link] = endIndex;
}

@Override
public void run() {
int cols = matrix2[0].length;

for (int i = startIndex; i <= endIndex; i++) {


for (int j = 0; j < cols; j++) {
for (int k = 0; k < MATRIX_SIZE; k++) {
result[i][j] += matrix1[i][k] * matrix2[k][j];
}
}
}
}
}
}

Common questions

Powered by AI

Critical elements include proper synchronization to prevent race conditions, careful distribution of workload among threads to avoid idleness and ensure balanced utilization, and managing potential data inconsistencies through appropriate synchronization mechanisms like locks and barriers. The overhead of thread creation and context-switching must be minimized relative to the computation work to retain efficiency. Exception handling is crucial to prevent abrupt thread termination disrupting execution flow. Equally, understanding the underlying hardware, like CPU cores and memory architecture, is important to design the workload. Proper optimization of these factors ensures data integrity and maximizes the efficiency of multithreaded computations .

The Java program creates two threads, each responsible for printing either even or odd numbers. It uses a shared lock object to synchronize the threads. The evenThread and oddThread take turns to print numbers by checking a boolean flag 'isEvenTurn'. Each thread enters a synchronized block, and if it is not their turn, they call lock.wait() to release the monitor and wait. Once a thread prints a number, it changes the value of 'isEvenTurn', calls lock.notify() to wake up the other thread, and then exits the synchronized block. This ensures that only one thread prints at a time, avoiding simultaneous access issues .

Merge sort divides the array into smaller segments, allowing multi-threaded environments to handle each segment concurrently. This division reduces the load on each thread, enabling faster handling of smaller parts. Each thread sorts its segment in parallel, minimizing the overall sorting time. After the threads finish sorting their respective segments, the main program merges the segments using the merge sort technique, ensuring that the fully sorted array is produced efficiently. This approach leverages concurrent processing to significantly enhance sorting speed, especially beneficial for large arrays where single-threaded sorting would be slower .

The program employs a divide-and-conquer strategy using multiple threads for sorting. The array is divided into segments, with each thread responsible for sorting one segment through the SortTask class, which implements the Runnable interface. Each thread sorts its assigned segment independently. After the threads have completed their tasks (ensured by calling thread.join()), the program performs a merge sort on the entire array. This final step combines the sorted segments into a fully sorted array, ensuring correctness and completeness .

Benefits of using multiple threads include improved performance by executing different parts of the computation concurrently, thus reducing the overall processing time compared to a single-threaded approach. It also allows better utilization of CPU resources, especially on multi-core processors. However, drawbacks include increased complexity in program design, potential for race conditions if synchronization is not handled correctly, and the overhead of thread creation and management. If the tasks are not evenly distributed among the threads, it can lead to inefficient use of resources, where some threads might finish early and remain idle while others are still processing .

The responsibilities are divided by assigning specific rows of the result matrix to different threads. The size of the matrix is divided by the number of threads (NUM_THREADS), creating segments of rows. Each thread, represented by an instance of MultiplicationTask, calculates the elements of its assigned segment by performing multiplication of corresponding rows from matrix1 and columns from matrix2. The startIndex and endIndex determine the rows each thread will handle, ensuring that threads work independently on different parts of the matrix .

The lock object functions as a mutual exclusion tool, ensuring that only one thread can execute within the synchronized block at any given time. This prevents race conditions where both evenThread and oddThread might attempt to print simultaneously, leading to jumbled output. The lock, combined with wait-notify mechanism, ensures that threads alternate correctly between printing even and odd numbers. When a thread waits, it releases the lock, allowing the other thread to enter its synchronized block, ensuring orderly execution and preventing concurrent access, which is critical for maintaining the program's correct behavior .

Potential pitfalls include the risk of deadlocks if locks are not released properly, lost notifications if notify is called before a thread has entered waiting state, and thread starvation where a thread might be consistently unable to acquire the lock. In the even-odd program, if exceptions occur without proper handling, or if threads do not correctly toggle the 'isEvenTurn' flag, it could lead to infinite waiting or missed turns, disrupting the sequence of number printing. Additionally, using wait and notify requires careful management of synchronicity to avoid these issues, emphasizing the need for thorough understanding of thread life cycles and synchronization .

The algorithm used is the merge part of the merge sort algorithm. It is appropriate for this context because it efficiently combines the individually sorted segments of the array into one fully sorted array. The merge process is inherently suited for handling sorted data streams, as it operates in linear time relative to the number of items being merged. This property makes it highly efficient after the initial segments have been sorted independently, providing a seamless way to combine these segments into a single, sorted output .

Thread joining ensures that the main program thread waits for the completion of all individual sorting threads before proceeding to the merge step. This guarantees that each portion of the array is fully sorted individually before attempting to merge them into a single sorted array. Without joining, there is a risk that the merging process starts before all sorting threads finish their tasks, resulting in an incorrectly sorted array. Thus, joining serves to synchronize these operations, ensuring all threads complete their sorting tasks first, contributing to the overall correctness .

You might also like