Commit 769ba4d6 authored by ubay.alshamali's avatar ubay.alshamali

Initial commit

parents
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="MultiThreadsPrimeNumber" />
</profile>
</annotationProcessing>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>MultiThreadsPrimeNumber</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package Data;
//this class is built with a createData method just for creating a list of random numbers with a chosen size
//thus create an input for our program
public class Data
{
public static int[] createData(int size)
{
int[] res = new int[size];
for (int i = 0; i < size; i++)
{
res[i] = (int) (Math.random() * 10);
}
return res;
}
}
package Data;
//this class is defining an object type (close to structure than a class)
//to encapsulate the meaning of what is a part of the data created in the Data class
//which can be defined by only determining the start and finish indexes of the input data list
public class DataPart
{
private final int start;
private final int finish;
public DataPart(int start, int finish)
{
this.start = start;
this.finish = finish;
}
public int getStart()
{
return start;
}
public int getFinish()
{
return finish;
}
}
import Data.Data;
import Organizer.*;
import java.util.Arrays;
public class Main
{
public static void main(String[] args)
{
int size = 10;
int[] data = Data.createData(size);
int threadCount = 5;
System.out.println("data: " + Arrays.toString(data));
System.out.println("Organizer 1: there is [" + Organizer_1.Count(data, threadCount) + "] prime numbers in the list above");
System.out.println("Organizer 2: there is [" + Organizer_2.Count(data, threadCount) + "] prime numbers in the list above");
System.out.println("Organizer 3: there is [" + Organizer_3.Count(data, threadCount) + "] prime numbers in the list above");
System.out.println("Organizer 4: there is [" + Organizer_4.Count(data, threadCount) + "] prime numbers in the list above");
System.out.println("Organizer 5: there is [" + Organizer_5.Count(data, threadCount) + "] prime numbers in the list above");
}
}
package Organizer;
import Data.DataPart;
import PrimeNumberCounter.PrimeNumberCounterThread;
import Worker.WorkPartitioner;
import java.util.ArrayList;
import java.util.List;
//this class represent one type of the foreman or literally the organizer
//it is the class that organize (split and distribute the data to the workers (threads) and aggregate the results )
public class Organizer_1
{
public static int Count(int[] data, int threadCount)
{
List<PrimeNumberCounterThread> primeNumberCounters = new ArrayList<>();
List<DataPart> parts = WorkPartitioner.partitions(data.length, threadCount);
for (int i = 0; i < threadCount; i++)
{
primeNumberCounters.add(new PrimeNumberCounterThread(parts.get(i), data));
}
for (int i = 0; i < threadCount; i++)
{
primeNumberCounters.get(i).start();
}
for (int i = 0; i < threadCount; i++)
{
try
{
primeNumberCounters.get(i).join();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
int count = 0;
for (PrimeNumberCounterThread primeCounterThread : primeNumberCounters)
{
count += primeCounterThread.getCount();
}
return count;
}
}
package Organizer;
import Data.DataPart;
import PrimeNumberCounter.PrimeNumberCounterRunnable;
import Worker.WorkPartitioner;
import java.util.ArrayList;
import java.util.List;
//this class represent one type of the foreman or literally the organizer
//it is the class that organize (split and distribute the data to the workers (threads) and aggregate the results )
public class Organizer_2
{
public static int Count(int[] data, int threadCount)
{
List<PrimeNumberCounterRunnable> primeNumberCounters = new ArrayList<>();
List<DataPart> parts = WorkPartitioner.partitions(data.length, threadCount);
for (int i = 0; i < threadCount; i++)
{
primeNumberCounters.add(new PrimeNumberCounterRunnable(parts.get(i), data));
}
for (int i = 0; i < threadCount; i++)
{
primeNumberCounters.get(i).startThread();
}
for (int i = 0; i < threadCount; i++)
{
try
{
primeNumberCounters.get(i).joinThread();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
int count = 0;
for (PrimeNumberCounterRunnable primeCounterRunnable : primeNumberCounters)
{
count += primeCounterRunnable.getCount();
}
return count;
}
}
package Organizer;
import Data.DataPart;
import PrimeNumberCounter.PrimeNumberCounterThread;
import Worker.WorkPartitioner;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//this class represent one type of the foreman or literally the organizer
//it is the class that organize (split and distribute the data to the workers (threads) and aggregate the results )
public class Organizer_3
{
public static int Count(int[] data, int threadCount)
{
List<PrimeNumberCounterThread> primeNumberCounters = new ArrayList<>();
List<DataPart> parts = WorkPartitioner.partitions(data.length, threadCount);
for (int i = 0; i < threadCount; i++)
{
primeNumberCounters.add(new PrimeNumberCounterThread(parts.get(i), data));
}
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
for (PrimeNumberCounterThread counter : primeNumberCounters)
{
executor.execute(counter);
}
executor.shutdown();
while (!executor.isTerminated())
{
//System.out.println("Processing....");
}
return primeNumberCounters.stream().mapToInt(PrimeNumberCounterThread::getCount).sum();
}
}
package Organizer;
import Data.DataPart;
import PrimeNumberCounter.PrimeNumberCounterCallable;
import Worker.WorkPartitioner;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
//this class represent one type of the foreman or literally the organizer
//it is the class that organize (split and distribute the data to the workers (threads) and aggregate the results )
public class Organizer_4
{
public static int Count(int[] data, int threadCount)
{
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
List<PrimeNumberCounterCallable> primeNumberCounters = new ArrayList<PrimeNumberCounterCallable>();
List<DataPart> parts = WorkPartitioner.partitions(data.length, threadCount);
for (DataPart part : parts)
{
primeNumberCounters.add(new PrimeNumberCounterCallable(part, data));
}
List<Future<Integer>> results;
try
{
results = executor.invokeAll(primeNumberCounters);
}
catch (InterruptedException e)
{
System.err.println("Cannot invoke the threads.");
return -1;
}
executor.shutdown();
int count = 0;
for (Future<Integer> future : results)
{
try
{
count += future.get();
}
catch (InterruptedException | ExecutionException e)
{
System.err.println("Cannot get the results from threads.");
return -2;
}
}
return count;
}
}
package Organizer;
import Data.DataPart;
import PrimeNumberCounter.PrimeNumberCounterCallable;
import Worker.WorkPartitioner;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
//this class represent one type of the foreman or literally the organizer
//it is the class that organize (split and distribute the data to the workers (threads) and aggregate the results )
public class Organizer_5
{
public static int Count(int[] data, int threadCount)
{
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
List<Future<Integer>> results = new ArrayList<Future<Integer>>();
List<DataPart> parts = WorkPartitioner.partitions(data.length, threadCount);
for (DataPart part : parts)
{
results.add(executor.submit(new PrimeNumberCounterCallable(part, data)));
}
executor.shutdown();
while (!executor.isTerminated())
{
//System.out.println("Processing...");
}
int count = 0;
for (Future<Integer> future : results)
{
try
{
count += future.get();
}
catch (InterruptedException | ExecutionException e)
{
System.err.println("Cannot get the results from threads.");
return -2;
}
}
return count;
}
}
package PrimeNumberCounter;
import Data.DataPart;
import Worker.Worker;
//this class is considered as a special type of worker that is used for our program
public class PrimeNumberCounter extends Worker
{
protected int PrimeNumberCount;
public PrimeNumberCounter(DataPart part, int[] d)
{
super(part, d);
}
public int getCount()
{
return PrimeNumberCount;
}
public static boolean isPrime(int n)
{
if (n <= 1)
{
return false;
}
if (n <= 3)
{
return true;
}
if (n % 2 == 0 || n % 3 == 0)
{
return false;
}
for (int i = 5; i * i <= n; i += 6)
{
if (n % i == 0 || n % (i + 2) == 0)
{
return false;
}
}
return true;
}
}
package PrimeNumberCounter;
import Data.DataPart;
import java.util.concurrent.Callable;
//this class is type of the special worker (prime number counter)
public class PrimeNumberCounterCallable extends PrimeNumberCounter implements Callable<Integer>
{
public PrimeNumberCounterCallable(DataPart part, int[] d)
{
super(part, d);
}
@Override
public Integer call() throws Exception
{
this.PrimeNumberCount = 0;
for (int i = start; i < finish; i++)
{
if (isPrime(data[i]))
{
this.PrimeNumberCount += 1;
}
}
return PrimeNumberCount;
}
}
package PrimeNumberCounter;
import Data.DataPart;
//this class is type of the special worker (prime number counter)
public class PrimeNumberCounterRunnable extends PrimeNumberCounter implements Runnable
{
private Thread thread;
public PrimeNumberCounterRunnable(DataPart part, int[] d)
{
super(part, d);
}
@Override
public void run()
{
this.PrimeNumberCount = 0;
for (int i = start; i < finish; i++)
{
if (isPrime(data[i]))
{
this.PrimeNumberCount += 1;
}
}
}
public void startThread()
{
thread = new Thread(this);
thread.start();
}
public void joinThread() throws InterruptedException
{
thread.join();
}
}
package PrimeNumberCounter;
import Data.DataPart;
//this class is a thread that also serve the same objective, as the other workers
public class PrimeNumberCounterThread extends Thread
{
private int start;
private int finish;
private int[] data;
private int prime_number_count;
public PrimeNumberCounterThread(DataPart part, int[] d)
{
start = part.getStart();
finish = part.getFinish();
data = d;
}
@Override
public void run()
{
prime_number_count = 0;
for (int i = start; i < finish; i++)
{
if (PrimeNumberCounter.isPrime(data[i]))
{
prime_number_count += 1;
}
}
}
public int getCount()
{
return prime_number_count;
}
}
import PrimeNumberCounter.PrimeNumberCounter;
//this class is used for testing
public class SequentialCounter
{
public static int Count(int[] data)
{
int result = 0;
for(int i = 0; i<data.length; i++)
{
if(PrimeNumberCounter.isPrime(data[i]))
{
result += 1;
}
}
return result;
}
}
package Worker;
import Data.DataPart;
import java.util.ArrayList;
import java.util.List;
//this class define a tool (method) to partition the data according to the number of the workers (thread)
//which will be used by the organizer (foreman)
public class WorkPartitioner
{
public static List<DataPart> partitions(int size, int worker_count)
{
List<DataPart> parts = new ArrayList<>();
int part = (int) Math.ceil((double) size / worker_count);
for (int i = 0; i < worker_count; i++)
{
int start = i * part;
int finish = Math.min((i + 1) * part, size);
parts.add(new DataPart(start, finish));
}
return parts;
}
}
package Worker;
import Data.DataPart;
// this class define what is a worker which will be used a thread
public class Worker
{
protected int start;
protected int finish;
protected int[] data;
public Worker(DataPart part, int[] d)
{
start = part.getStart();
finish = part.getFinish();
data = d;
}
public int[] getData()
{
return data;
}
}
import Data.Data;
import Organizer.*;
import org.junit.BeforeClass;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
public class OrganizersTest
{
private static int size;
private static int[] data;
private static int result;
@BeforeClass
public static void initialize() {
size = 10;
data = Data.createData(size);
result = SequentialCounter.Count(data);
}
private static void testAll(int threadCount) {
assertEquals(result, Organizer_1.Count(data,threadCount));
assertEquals(result, Organizer_2.Count(data,threadCount));
assertEquals(result, Organizer_3.Count(data,threadCount));
assertEquals(result, Organizer_4.Count(data,threadCount));
assertEquals(result, Organizer_5.Count(data,threadCount));
}
@Test
public void testSingleThread() {
testAll(1);
}
@Test
public void testTwoThread() {
testAll(2);
}
@Test
public void testFourThread() {
testAll(4);
}
@Test
public void testEightThread() {
testAll(8);
}
@Test
public void testSixteenThread() {
testAll(16);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment