I have a method that counts the prime numbers from 1 to x and when x is a really large number like 1000000000, I would like to split the work between threads. My prime counter accepts 1 parameter, x, that is the last number to check whether it is prime or not. This method returns the count, integer of primes in which the method calculated. I know that I can have something like:
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
int primes = primeCounter(1000000);
System.out.println("There are: " + primes+ " primes in betweem 1 and " + 1000000);
}
});
But how can I continue from 1000000 to 100000000 with another thread and join those two threads?
First, like mentioned in the comment, change your primecounter so that ist accepts a range.
Second, create a class which extends Thread, e.g:
class MyThread extends Thread {
long start;
long stop;
int primes = 0;
MyThread(long start, long stop) {
this.start = start;
this.stop = stop;
}
#Override
public void run() {
primes = primeCounter(start, stop);
System.out.println("There are: " + primes + " primes in betweem " + start + " and " + stop);
}
private int primeCounter(long start, long stop) {
int counter = 0;
//.....
return counter;
}
}
Then you can create your threads, starting them and waiting until they are all finished:
long max = 1000000000;
long packetSize = 1000000;
List<MyThread> threads = new ArrayList<>();
long start = 0;
for (int i = 0; i < (int) (max / packetSize); i++) {
threads.add(new MyThread(start, start = start + packetSize));
}
threads.forEach((Thread t)-> t.start());
threads.forEach((Thread t)-> { try {t.join();}catch(InterruptedException e) {throw new RuntimeException(e);}});
The example is very simple, change it to your needs and don't forget the exception handling :)
Related
all
I'm trying to check multithread processing of the some data set that contain number from 1 to N. For example, I want to sum all this number:
1) Hold the sum (result).
public class ResultHolder {
public static AtomicLong total_time = new AtomicLong(0);
public static Long sum = 0l;
public Long getSum() {
return sum;
} // END: getSum()
#PostConstruct
public void init() {
} // END: init()
public void setSum(Long sum) {
this.sum = sum;
} // END: setSum()
public void printSum() {
System.out.println("Sum is " + sum);
}
public void clearSum() {
sum = 0l;
}
} // ENDC: ResultHolder
2) Process part of number's set:
public class SumProcessor {
private static int global_id = 0;
final public int processor_id;
private final ArrayList<Long> numbers;
private Long processor_sum = 0l;
#Autowired
private final ResultHolder sumHoldder = null;
public SumProcessor(ArrayList<Long> numbers) {
this.numbers = numbers;
processor_id = ++global_id;
} // END: constructor
public void work() throws Exception {
long t1 = new java.util.Date().getTime();
int i = 0;
try {
if (numbers == null) throw new Exception("Не удалось получить массив чисел.");
for (i = 0; i < numbers.size(); i++) {
Long o = null;
try {
o = numbers.get(i);
if (o == null) throw new Exception("no number");
} catch (Exception e) {
throw new Exception("Ошибка извлечения числа из массива: " + e);
}
processor_sum += o;
} // END: for
if (sumHoldder == null) throw new Exception("No sum holder");
synchronized (sumHoldder) {
sumHoldder.setSum(sumHoldder.getSum() + processor_sum);
}
long t2 = new java.util.Date().getTime();
this.sumHoldder.total_time.addAndGet(t2 - t1);
} catch (Exception e) {
System.out.println("Work() error (" + i + ") " + e);
}
return;
} //END: method1
#PostConstruct
public void init() {
System.out.println("Initializated B: " + this);
} //END: method2
#PreDestroy
public void destroy() {
System.out.println("Destroy B: " + this);
} //END: method3
#Override
public String toString() {
return "" +
"Processor " + processor_id + " " +
"contain " + numbers.size() + " " +
"numbers from " + numbers.get(0) +
" to " + numbers.get(numbers.size() - 1);
} //END: toString()
} //END: class SumProcessor
3) Very simple profiler (calcs processing time)
#Aspect
public class MethodLoggerBasic {
#Pointcut("execution(* *.work(..))")
void around_work() {};
#Around("around_work()")
public void logMethodName(ProceedingJoinPoint joinPoint) throws Throwable {
long starttime = new Date().getTime();
joinPoint.proceed();
long endtime = new Date().getTime();
long time = endtime - starttime;
MainApp.time += time;
} // END:
} // ENDC
4) Main program (can start processing linear or in parallel)
public class MainApp {
static AnnotationConfigApplicationContext context;
public static long time = 0l;
public final static int SIZE = 40_000_000;
public final static int DIVIDE_FACTOR = 4;
public static ArrayList<Long>[] numbers = new ArrayList[DIVIDE_FACTOR];
public static ArrayList<SumProcessor> processors = new ArrayList<>();
public static void main(String[] args) throws Exception {
context = new AnnotationConfigApplicationContext(myConfig.class);
// form 4 datasets
int part_size = SIZE / DIVIDE_FACTOR;
int i;
int j;
for (j = 0; j < DIVIDE_FACTOR; j++) {
numbers[j] = new ArrayList<>();
for (i = 0; i < (int) part_size; i++) {
numbers[j].add(((j * part_size) + i + 1l));
}
}
// create 4 processors (bean)
for (i = 0; i < DIVIDE_FACTOR; i++) {
SumProcessor bean = context.getBean(SumProcessor.class, numbers[i]);
if (bean == null) throw new Exception("Error recive bean SumProcessor.class");
processors.add(bean);
}
// creates 4 threads fro processors
thread_process thread1 = new thread_process();
thread_process thread2 = new thread_process();
thread_process thread3 = new thread_process();
thread_process thread4 = new thread_process();
ResultHolder a;
a = context.getBean(ResultHolder.class);
try {
boolean isByPool = true; // flag
time = 0;
if (isByPool) {
System.out.println("-------------------");
System.out.println("Multithread compute");
System.out.println("-------------------");
ExecutorService pool = new ThreadPoolExecutor(
4,
4,
0,
TimeUnit.MICROSECONDS,
new ArrayBlockingQueue<>(4)
);
List<Callable<Boolean>> tasks = new ArrayList();
tasks.add(thread1);
tasks.add(thread2);
tasks.add(thread3);
tasks.add(thread4);
pool.invokeAll(tasks);
pool.shutdown();
pool.awaitTermination(60, TimeUnit.SECONDS);
} else {
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread1.join();
thread2.join();
thread3.join();
thread4.join();
}
a.printSum();
a.clearSum();
System.out.println("total time is " + a.total_time);
System.out.println("basic time is " + MainApp.time);
System.out.println("-------------");
System.out.println("Single thread");
System.out.println("-------------");
ArrayList<Long> numbers_tolal = new ArrayList<>();
for (i = 0; i < SIZE; i++) {
numbers_tolal.add((i + 1l));
}
SumProcessor sumProcessor = context.getBean(SumProcessor.class, numbers_tolal);
a.total_time.set(0l);
time = 0l;
sumProcessor.work();
a.printSum();
System.out.println("total time is " + a.total_time);
System.out.println("basic time is " + MainApp.time);
} catch (Exception e) {
throw new Exception("MainApp error: " + e);
}
context.close();
} // END: main
} // END: class MainApp
5) Thread process:
public class thread_process extends Thread implements Callable, Runnable {
static int index = 0;
#Override
public void run() {
try {
SumProcessor next = MainApp.processors.get(index++);
if (next == null) {
System.out.println("Нет процессора");
System.exit(-1);
}
next.work();
System.out.println("Thread " + this + " complete!");
} catch (Exception e) {
System.out.println("Error in thread " + this + ": " + e);
}
} //END: run()
#Override
public Boolean call() throws Exception {
run();
return true;
} //END: call()
}; //END: class thread_process
The output is:
Initializated B: Processor 1 contain 10000000 numbers from 1 to 10000000
Initializated B: Processor 2 contain 10000000 numbers from 10000001 to 20000000
Initializated B: Processor 3 contain 10000000 numbers from 20000001 to 30000000
Initializated B: Processor 4 contain 10000000 numbers from 30000001 to 40000000
-------------------
Multithread compute
-------------------
Thread Thread[Thread-3,5,main] complete!
Thread Thread[Thread-4,5,main] complete!
Thread Thread[Thread-2,5,main] complete!
Thread Thread[Thread-1,5,main] complete!
Sum is 800000020000000
total time is 11254
basic time is 11254
-------------
Single thread
-------------
Initializated B: Processor 5 contain 40000000 numbers from 1 to 40000000
Sum is 800000020000000
total time is 6995
basic time is 6995
Is there a method to make it faster in parallel than linear? Or do I perhaps not need to fork this task? Or maybe my profiler is not so good...
GitHub project
You are trying to perform a sequential task using multithreading, that isn't correct use of multithreading. Here, you have a resource for which you need to perform some work. You are using multiple threads to distribute that work, but at the same time, you are blocking one thread when the other thread is using the resource. So, why have worker threads in the first place if you don't want them to access the resource in parallel.
If not necessary, you can drop the Set implementation of the dataset and use List or Arrays where you can access elements using indices without blocking the worker thread.
Update 1: Just add one more line after pool.shutdown() call.
pool.shutdown(); // starts thread shutdown, or force execution of worker threads
pool.awaitTermination(60, TimeUnit.SECONDS); // blocks main thread until thread pool finishes
// ...
// now you can do your single thread task
Also, don't create too many threads since a single thread is fast enough to handle million array elements.
Update 2: So, I don't know why but putting the single thread out of try block seems to get me the expected result.
public class MainApp {static AnnotationConfigApplicationContext context;
public static long time = 0;
public final static int SIZE = 28_000_000;
public final static int DIVIDE_FACTOR = 4;
public static ArrayList<Long>[] numbers = new ArrayList[DIVIDE_FACTOR];
public static ArrayList<SumProcessor> processors = new ArrayList<>();
public static void main(String[] args) throws Exception {
context = new AnnotationConfigApplicationContext(AppConfig.class);
ResultHolder a = context.getBean(ResultHolder.class);
// form 4 datasets
int part_size = SIZE / DIVIDE_FACTOR;
int i;
int j;
for (j = 0; j < DIVIDE_FACTOR; j++) {
numbers[j] = new ArrayList<>(part_size);
for (i = 0; i < (int) part_size; i++) {
numbers[j].add(((j * part_size) + i + 1l));
}
}
// create 4 processors (bean)
for (i = 0; i < DIVIDE_FACTOR; i++) {
SumProcessor bean = context.getBean(SumProcessor.class, numbers[i]);
if (bean == null) throw new Exception("Error receive bean SumProcessor.class");
processors.add(bean);
}
// creates 4 threads fro processors
thread_process thread1 = new thread_process();
thread_process thread2 = new thread_process();
thread_process thread3 = new thread_process();
thread_process thread4 = new thread_process();
try {
boolean isByThread = true; // flag
time = 0;
System.out.println("-------------------");
System.out.println("Multithread compute");
System.out.println("-------------------");
ExecutorService pool = new ThreadPoolExecutor(
4,
4,
0,
TimeUnit.MICROSECONDS,
new LinkedBlockingDeque<>(4) // or ArrayBlockingDeque<>(4)
);
List<Callable<Boolean>> tasks = new ArrayList();
tasks.add(thread1);
tasks.add(thread2);
tasks.add(thread3);
tasks.add(thread4);
List<Future<Boolean>> futures = pool.invokeAll(tasks);
pool.shutdown();
pool.awaitTermination(60, TimeUnit.SECONDS);
System.out.println("Time is: " + time);
a.printSum();
a.clearSum();
time = 0;
} catch (Exception e) {
throw new Exception("MainApp error: " + e);
} // <---- moved single thread out of try block
ArrayList<Long> numbers_total = new ArrayList<>(SIZE);
for (i = 0; i < SIZE; i++) {
numbers_total.add((i + 1l));
}
System.out.println("-------------");
System.out.println("Single thread");
System.out.println("-------------");
SumProcessor sumProcessor = context.getBean(SumProcessor.class, numbers_total);
sumProcessor.work();
System.out.println("Time is: " + time);
a.printSum();
a.clearSum();
time = 0;
context.close();
} // END: main
}
Output:
Initialized B: Processor 1 contain 7000000 numbers from 1 to 7000000
Initialized B: Processor 2 contain 7000000 numbers from 7000001 to 14000000
Initialized B: Processor 3 contain 7000000 numbers from 14000001 to 21000000
Initialized B: Processor 4 contain 7000000 numbers from 21000001 to 28000000
-------------------
Multithread compute
-------------------
Thread[Thread-3,5,main] complete task.
Thread[Thread-2,5,main] complete task.
Thread[Thread-1,5,main] complete task.
Thread[Thread-4,5,main] complete task.
Time is: 5472
Sum is 392000014000000
-------------
Single thread
-------------
Initialized B: Processor 5 contain 28000000 numbers from 1 to 28000000
Time is: 10653
Sum is 392000014000000
Output [Reverse order]:
-------------
Single thread
-------------
Initialized B: Processor 1 contain 28000000 numbers from 1 to 28000000
Time is: 2265
Sum is 392000014000000
Initialized B: Processor 2 contain 7000000 numbers from 1 to 7000000
Initialized B: Processor 3 contain 7000000 numbers from 7000001 to 14000000
Initialized B: Processor 4 contain 7000000 numbers from 14000001 to 21000000
Initialized B: Processor 5 contain 7000000 numbers from 21000001 to 28000000
-------------------
Multithread compute
-------------------
Thread[Thread-2,5,main] complete task.
Thread[Thread-4,5,main] complete task.
Thread[Thread-1,5,main] complete task.
Thread[Thread-3,5,main] complete task.
Time is: 2115
Sum is 392000014000000
This is a Java Program to Find The Number with Largest Divisors from 1-500000.
public class Medium2 {
static int count1 = 1;
static int count2 = 1;
static int big_count = 0;
static int big = 0;
Main method
public static void main(String[] args) {
Runnable runnable1 = new Runnable() {
public void run() {
The implementation goes here
for (int num = 1; num <= 500000; num++) {
for (int i = 2; i <= num; i++) {
if (num % i == 0) { //Actual Logic
count1++;
}
}
if (count1 > big_count) {
big_count = count1; //Number of Divisors
big = num; //Largest Number
}
count1 = 1;
}
}
};
And the thread execution
Thread thread1 = new Thread(runnable1); //Threads
Thread thread2 = new Thread(runnable1);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException ie) {
;
}
System.out.println("Biggest: " + big + "\nNumber of Divisors for " + big + " = " + big_count);
}
}
But it gives different answers every time. The actual answer is : 498960 and 200 Divisors
Concerning your goal, your implementation should probably have problems. Since big_count and big is common for both threads and don't have any protection when threads are trying to modify those, your program should create errors.
Other than that, you are also not utilizing 2 threads, since both threads are doing calculation from 1 to 500000.
Since your calculation logic seems ok, you should get your desired output when you try with single thread.
If you want it to do by two threads, you can easily try this. (just to verify, not the nicest way)
You should have big_count1, big1 and big_count2, big2. So that variables whose names end with '1' is only using by thread1 and variables whose names end with '2' is only using by thread2.
Assign thread1 to check from 1 to 250000 and thread2 to from 250001 to 500000.
After join() s, just compare big_count1 and big_count2, then you can deduce the final answer. :))
This question already has answers here:
wait until all threads finish their work in java
(17 answers)
Closed 8 years ago.
Hello in my exercise I need to show resource access problems with multi threads.
I need to increment indexes of shared (between threads) int table called histogramTable[]the size of table is known, and data is in file. Each thread got it own range, called interval. For example: I have 4 threads and every threads getting the following indexes:
Thread 1: 0 - 1_000_000
Thread 2: 1_000_000 - 2_000_000
Thread 3: 2_000_000 - 3_000_000
Thread 4: 3_000_000 - 4_000_000
And here is my problem, once you start a program with given number on threads, it's threadsNumber variable, it seems that only one thread is running. Because sum of bytes is always tabSize / threadsNumber. For above example it's 1_000_000 bytes.
With problem of thread access it should be 3_800_000 - 4_000_000 bytes. Can you tell me what I'm doing wrong?
I'm giving you whole code cause in my opinion its short. Also there is a commented out funcion called randomizeBytes() to fastly generate byte file.
Ex.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Ex2 {
private static int threadsNumber = 4, tabSize = 4000000;
public static int threadsCounter;
public static byte[] dataTab = loadBytes();
public static byte[] loadBytes() {
byte data[] = new byte[tabSize];
Path path = Paths.get("dane.txt");
try {
data = Files.readAllBytes(path);
}
catch (IOException e) {
e.printStackTrace();
}
return data;
}
/*private byte[] randomizeBytes() {
Path path = Paths.get("binaryData.txt");
byte bytes[] = new byte[tabSize];
new Random().nextBytes(bytes);
try {
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}*/
public static void runThreads(){
threadsCounter = threadsNumber;
int interval = tabSize / threadsNumber;
int endIndex = 0;
Thread[] threads = new Thread[threadsNumber];
MyThread w;
for(int i = 0 ; i < threadsNumber ; i ++){
endIndex = (i + 1) * interval;
if(endIndex >= tabSize)
endIndex = tabSize;
w = new MyThread(interval * i , endIndex);
threads[i] = new Thread(w);
threads[i].start();
if(threads[i].isAlive())
System.out.println("Thread number: " + i + " started and alive, indexes: " + interval*i + " - " + endIndex );
}
}
public synchronized static int decrementThreads(){
return --threadsCounter;
}
public static void main(String args[]){
runThreads();
}
}
MyTherad.java
public class MyThread implements Runnable{
private byte table[] = Ex2.dataTab;
int startIndex,endIndex,temp;
private int histogramTable[] = new int[256] ;
private long timeStart, timeStop;
public MyThread(int startIndex, int endIndex){
this.startIndex = startIndex;
this.endIndex = endIndex;
}
#Override
public void run() {
timeStart = System.currentTimeMillis();
for(int i = startIndex ; i < endIndex ; i ++) {
temp = Byte.toUnsignedInt(table[i]);
histogramTable[temp]++;
}
timeStop = System.currentTimeMillis();
System.out.println("Threads working: " + Ex2.threadsCounter);
if(Ex2.decrementThreads() == 0) printSummary();
}
public void printSummary() {
int sum = 0;
for(int i : histogramTable) System.out.print(i + " ");
System.out.println();
for(int i = 0 ; i < 256 ; i ++)
sum += histogramTable[i];
System.out.println("Bytes: " + sum);
System.out.println("Task complete in: " + (timeStop - timeStart) + "ms");
}
}
Check out Thread.join(). Look at the explanation in the answer at Java Multithreading concept and join() method.
Situation
I am trying to get familiar with threads in Java. For that reason I modified a program listing I found in a book. What is does is pretty simple:
It creates a boolean[]-array with 100.000.000 elements.
It randomly fills that array's elements with true or false using NUMBER_OF_SERVERS threads.
Finally it scans that array with NUMBER_OF_SERVERS threads and counts how many entries are set to true
For further details, please see the code below on the bottom of this post.
Problem
When I run the code with different number of threads and measure the runtime, I get a very strange result; or at least a behaviour that I do not understand: The BuildService-Thread consumes MORE runtime when I use MORE threads. When building the entire array (based on random truedistribution) in just one thread that takes about 10 seconds. Next, when I use four threads I would expect the runtime to decrease. However, I get a time consumption of about 17 seconds.
My ScanService works as expected: Time consumption decreases with more threads.
Please see the following chart for details:
However, if change one line in my code and replace the if ((int) ((Math.random() * 2d)) == 0)-statement (for random true-distribution) with if (i % 2 == 0) (thus, every second item will be true) I get a behaviour I would expect:
Questions
So, my questions are:
Why do MORE threads lead to a LONGER runtime when using Math.random() function?
Vice versa, why does the runtime DECREASE when using only ONE thread using the exact same function?
What "general rules" can be derived from this behaviour when it comes down to dealing with threads?
Background info
The code was run on an Intel core i3.
Code
public class AsynchService
{
private static final int ARRAY_SIZE = 100000000; //100.000.000
private static final int NUMBER_OF_SERVERS = 16;
private static final int HOW_MANY = ARRAY_SIZE / NUMBER_OF_SERVERS;
//build array asynch
public static boolean[] buildArrayAsynch()
{
//build array with NUMBER_OF_SERVERS-Threads
boolean[] array = new boolean[ARRAY_SIZE];
Thread[] buildServerThread = new Thread[NUMBER_OF_SERVERS];
long startTime = System.currentTimeMillis();
for (int i = 0; i < NUMBER_OF_SERVERS; i++)
{
int start = i * HOW_MANY;
int end = (i != NUMBER_OF_SERVERS - 1) ? (i + 1) * HOW_MANY - 1 : ARRAY_SIZE - 1;
buildServerThread[i] = new BuildService(array, i, start, end);
}
//synchronize and wait for result
int expectedResult = 0;
for (int i = 0; i < NUMBER_OF_SERVERS; i++)
{
try
{
buildServerThread[i].join();
}
catch (InterruptedException ex) {}
expectedResult += ((BuildService) buildServerThread[i]).getExpectedResult();
}
System.out.println("\nNumber of \"true\"s ==> Expected result: " + expectedResult);
System.out.println("Build duration: " + (System.currentTimeMillis() - startTime) + " ms\n");
return array;
}
//scan array asynch
public static int scanArrayAsynch(boolean[] array)
{
//create services and server-threads
Thread[] serverThread = new Thread[NUMBER_OF_SERVERS];
long startTime = System.currentTimeMillis();
for (int i = 0; i < NUMBER_OF_SERVERS; i++)
{
int start = i * HOW_MANY;
int end = (i != NUMBER_OF_SERVERS - 1) ? (i + 1) * HOW_MANY - 1 : ARRAY_SIZE - 1;
serverThread[i] = new ScanService(array, i, start, end);
}
//synchronize with servers, wait for server end
int result = 0;
for (int i = 0; i < NUMBER_OF_SERVERS; i++)
{
try
{
serverThread[i].join();
}
catch (InterruptedException ex) {}
result += ((ScanService) serverThread[i]).getResult();
}
System.out.println("Search duration: " + (System.currentTimeMillis() - startTime) + " ms");
return result;
}
public static void main(String[] args)
{
//build array
boolean[] array = buildArrayAsynch();
//scan array
int result = scanArrayAsynch(array);
//display result
System.out.println("\nResult: " + result);
}
}
class BuildService extends Thread
{
private boolean[] array;
private int start;
private int end;
private int expectedResult = 0;
public BuildService(boolean[] array, int serviceId, int start, int end)
{
this.array = array;
this.start = start;
this.end = end;
this.setName("BuildService " + serviceId);
this.start();
}
public int getExpectedResult()
{
return expectedResult;
}
public void run()
{
if (start < 0 || end >= array.length) throw new IndexOutOfBoundsException();
System.out.println(getName() + ": StartIndex = " + start + "; EndIndex = " + end);
long startTime = System.currentTimeMillis();
for (int i = start; i <= end; i++)
{
//if (i % 2 == 0)
if ((int) ((Math.random() * 2d)) == 0)
{
array[i] = true;
expectedResult++;
}
else
{
array[i] = false;
}
}
System.out.println(getName() + " finished! \"true\" elements: " + expectedResult + "; duration = " + (System.currentTimeMillis() - startTime) + "ms");
}
}
class ScanService extends Thread
{
private boolean[] array;
private int serviceId;
private int start;
private int end;
private int result = 0;
public ScanService(boolean[] array, int serviceId, int start, int end)
{
this.array = array;
this.serviceId = serviceId;
this.start = start;
this.end = end;
this.start();
}
public int getResult()
{
return result;
}
public void run()
{
if (start < 0 || end >= array.length) throw new IndexOutOfBoundsException();
System.out.println("Server " + serviceId + ": StartIndex = " + start + "; EndIndex = " + end);
for (int i = start; i <= end; i++)
{
if (array[i]) result++;
}
}
}
The devil is in the details. The documentation of Math.random() has the answer:
This method is properly synchronized to allow correct use by more than one thread. However, if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator.
To get around this issue, try creating an instance of java.util.Random for each instance of your BuildService class, and use that instead of Math.random(). A benefit of using java.util.Random is also that you don't have to do unnecessary double-int-arithmetic, but can simply use the nextBoolean() method.
You are probably seeing the effect of thread contention in Math.random(). Java 7 has the ThreadLocalRandom feature to avoid just this problem.
Your Code seems to be using 16 number of threads and each thread is using the Join method as in here
serverThread[i].join();
which seems to not use the full potential of threads.
when using the join you are actually saying the thread to wait till the other thread completes not running the threads in parallel.
you might want to use start method instead of join method.
Try running the changed code and post your analysis on time line.
Good luck learning
Taking Andreas Troelsen's answer into account I came up with the code shown below leading to the following runtimes.
Compared to what happened before, this solution now meets my expectations much better!
import java.util.Random;
class BuildService extends Thread
{
private boolean[] array;
private int start;
private int end;
private int expectedResult = 0;
private Random random = new Random();
public BuildService(boolean[] array, int serviceId, int start, int end)
{
this.array = array;
this.start = start;
this.end = end;
this.setName("BuildService " + serviceId);
this.start();
}
public int getExpectedResult()
{
return expectedResult;
}
public void run()
{
if (start < 0 || end >= array.length) throw new IndexOutOfBoundsException();
System.out.println(getName() + ": StartIndex = " + start + "; EndIndex = " + end);
long startTime = System.currentTimeMillis();
for (int i = start; i <= end; i++)
{
array[i] = random.nextBoolean();
if (array[i]) expectedResult++;
}
System.out.println(getName() + " finished! \"true\" elements: " + expectedResult + "; duration = " + (System.currentTimeMillis() - startTime) + "ms");
}
}
I've written a program to scan for amicable numbers (a pair of 2 numbers that the sum of all devisors of one equals to the other) It works ok and I'll include the entire code below.
I tried to get it to run with several threads so I moved the code to a class called Breaker and my main looks as follows:
Breaker line1 = new Breaker("thread1");
Breaker line2 = new Breaker("thread2");
Breaker line3 = new Breaker("thread3");
Breaker line4 = new Breaker("thread4");
line1.scanRange(1L, 650000L);
line2.scanRange(650001L, 850000L);
line3.scanRange(850001L, 1000000L);
line4.scanRange(1000001L, 1200001L);
Now this does shorten the time noticably, but this is not a smart solution and the threads end each on very different times.
What I'm trying to do, is to automate the process so that a master thread that has the entire range, will fire up sections of short ranges (10000) from the master range, and when a thread ends, to fire up the next section in a new thread, until the entire master range is done.
I've tried understanding how to use synchronized, notify() and wait() but after several tries all ended with different errors and unwanted behaviour.
Here is Breaker.java:
import java.util.ArrayList;
public class Breaker implements Runnable{
Long from, to = null;
String name = null;
Thread t = new Thread(this);
public Breaker(String name){
this.name = name;
}
public void scanRange(Long from, Long to){
this.from = from;
this.to = to;
t.start();
}
#Override
public void run() {
this.scan();
}
private void scan() {
ArrayList<ArrayList<Long>> results = new ArrayList<ArrayList<Long>>();
Long startingTime = new Long(System.currentTimeMillis() / 1000L);
Long lastReport = new Long(startingTime);
System.out.println(startingTime + ": Starting number is: " + this.from);
for (Long i = this.from; i <= this.to; i++) {
if (((System.currentTimeMillis() / 1000L) - startingTime ) % 60 == 0 && (System.currentTimeMillis() / 1000L) != lastReport) {
System.out.println((System.currentTimeMillis() / 1000L) + ": " + this.name + " DOING NOW " + i.toString() + ".");
lastReport = (System.currentTimeMillis() / 1000L);
}
ArrayList<Long> a = new ArrayList<Long>();
a = getFriendPair(i);
if(a != null) {
results.add(a);
System.out.println(this.name + ": FOUND PAIR! " + a.toString());
}
}
System.out.println((System.currentTimeMillis() / 1000L) + ": " + this.name + " Done. Total pairs found: " + results.size() +
". Total working time: " + ((System.currentTimeMillis() / 1000L) - startingTime) + " seconds.");
}
/**
* Receives integer and returns an array of the integer and the number who is it's
* pair in case it has any. Else returns null.
* #param i
* #return
*/
private static ArrayList<Long> getFriendPair(Long i) {
Long possibleFriend = getAndSumAllDevisors(i);
if (possibleFriend.compareTo(i) <= 0) return null;
Long sumOfPossibleFriend = getAndSumAllDevisors(possibleFriend);
if(sumOfPossibleFriend.equals(i)) {
ArrayList<Long> pair = new ArrayList<Long>();
pair.add(i);
pair.add(possibleFriend);
return pair;
}
return null;
}
private static Long getAndSumAllDevisors(Long victim) {
Long sum = new Long(1);
Long i = 2L;
Long k = new Long(0);
while ((k = i * i) <= victim) {
if ((victim % i) == 0) {
sum += i;
if (k == victim) return sum;
sum += (victim / i);
}
i++;
}
return sum;
}
}
Consider ExecutorService, which is backed by a thread pool. You feed it tasks and they get shuffled off to worker threads as they become available:
http://www.vogella.com/articles/JavaConcurrency/article.html#threadpools
What you need is a "Fixed Thread Pool". See http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool%28int%29
I would go for a ExecutorService with a fixed thread pool size. Your master thread can either feed directly to the executor service or you can disconnect them via a BlockingQueue. The Java Doc of the blocking queue describes the producer-consumer pattern quite nicely.
I ended up taking none of the answers but rather Marko's comment and implemented my solution using a Fork/Join framework. It works and runs almost at twice the speed of the none optimized version.
My code looks now like so:
main file (runner)
public class runner {
private static Long START_NUM = 1L;
private static Long END_NUM = 10000000L;
public static void main(String[] args) {
Long preciseStartingTime = new Long(System.currentTimeMillis());
ForkJoinPool pool = new ForkJoinPool();
WorkManager worker = new WorkManager(START_NUM, END_NUM);
pool.invoke(worker);
System.out.println("precise time: " + (System.currentTimeMillis() - preciseStartingTime));
}
WorkManager
I've defined here 3 class variables. from and to are set from a constructor which is called from the main file. And threshold which is the maximum amount of numbers the program will assign a single thread to compute serially.
As you can see in the code, it will recursively make the range smaller until it is small enough to to compute directly, then it calls Breaker to start breaking.
import java.util.concurrent.RecursiveAction;
public class WorkManager extends RecursiveAction{
Long from, to;
Long threshold = 10000L;
public WorkManager(Long from, Long to) {
this.from = from;
this.to = to;
}
protected void computeDirectly(){
Breaker b = new Breaker(from, to);
b.scan();
}
#Override
protected void compute() {
if ((to - from) <= threshold){
System.out.println("New thread from " + from + " to " + to);
computeDirectly();
}
else{
Long split = (to - from) /2;
invokeAll(new WorkManager(from, from + split),
new WorkManager(from + split + 1L, to));
}
}
}
Breaker (is no longer an implementation of of Runnable)
public class Breaker{
Long from, to = null;
public Breaker(Long lFrom, Long lTo) {
this.from = lFrom;
this.to = lTo;
}
public void scan() {
ArrayList<ArrayList<Long>> results = new ArrayList<ArrayList<Long>>();
Long startingTime = new Long(System.currentTimeMillis() / 1000L);
for (Long i = this.from; i <= this.to; i++) {
ArrayList<Long> a = new ArrayList<Long>();
a = getFriendPair(i);
if(a != null) {
results.add(a);
System.out.println((System.currentTimeMillis() / 1000L) + ": FOUND PAIR! " + a.toString());
}
}
}
/**
* Receives integer and returns an array of the integer and the number who is it's
* pair in case it has any. Else returns null.
* #param i
* #return
*/
private static ArrayList<Long> getFriendPair(Long i) {
Long possibleFriend = getAndSumAllDevisors(i);
if (possibleFriend.compareTo(i) <= 0) return null;
Long sumOfPossibleFriend = getAndSumAllDevisors(possibleFriend);
if(sumOfPossibleFriend.equals(i)) {
ArrayList<Long> pair = new ArrayList<Long>();
pair.add(i);
pair.add(possibleFriend);
return pair;
}
return null;
}
private static Long getAndSumAllDevisors(Long victim) {
Long sum = new Long(1);
Long i = 2L;
Long k = new Long(0);
while ((k = i * i) <= victim) {
if ((victim % i) == 0) {
sum += i;
if (k == victim) return sum;
sum += (victim / i);
}
i++;
}
return sum;
}
}