It is my first time posting a question. So please, go easy on me. :D
I am a student and I currently learning about multithreading.
My task is to determine the sorting of an array by dividing the array into two equal halves and
start a thread for each half, each thread being responsible for sorting the numbers assigned to it.
The thread is looking at how many numbers need to be sorted. If this is more than
a certain threshold, the thread will create 2 new threads, each sorting one half of the list. When those
threads are finished, the thread will merge the two (sorted) arrays together again. This creates a 'tree'
of active threads.
Threads that are not going to 'outsource' their work sort the arrays again with bubble sort
This is my code for the MultiThreading class:
public class MultiThreading implements Runnable {
private int[] wholeNumbers;
private int threshold;
public int[] getWholeNumbers() {
return wholeNumbers;
}
public MultiThreading(int[] wholeNumbers, int threshold) {
this.wholeNumbers = wholeNumbers;
this.threshold = threshold;
}
#Override
public void run() {
try {
sortArray(wholeNumbers, threshold);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public int[] sortArray(int[] wholeNumbers, int threshold) throws InterruptedException {
if (wholeNumbers.length < threshold) {
Sort.bubbleSort(wholeNumbers);
} else {
int[] left = Arrays.copyOfRange(wholeNumbers, 0, wholeNumbers.length / 2);
int[] right = Arrays.copyOfRange(wholeNumbers, wholeNumbers.length / 2, wholeNumbers.length);
Thread leftThread = new Thread(new MultiThreading(left, threshold));
Thread rightThread = new Thread(new MultiThreading(right, threshold));
leftThread.start();
rightThread.start();
leftThread.join();
rightThread.join();
wholeNumbers = Sort.merge(left,right);
}
return wholeNumbers;
}
}
This is how I initialize the class (here I try to change an already defined wholeNumbers array):
MultiThreading multiThreading = new MultiThreading(wholeNumbers, threshold);
Thread thread = new Thread(multiThreading);
thread.start();
thread.join();
wholeNumbers = multiThreading.getWholeNumbers();
I have been provided with the sorting and merging method, so they work just fine.
My problem is that it does not return the sorted array. I am not sure how to fix that.
It would be great if I receive some guidance. Thanks in advance.
SOLUTION
It turned out that the values in the merge method are not the correct ones that I should have used.
To fix this problem, I initialized the MultiThreading class two times, added them to the Threads, and used a get method in the merging function.
By doing that I ensure that the merging method receives the bubble-sorted whole numbers.
Here is my new Multithreading class:
public class MultiThreading implements Runnable {
private int[] wholeNumbers;
private int threshold;
public int[] getWholeNumbers() {
return wholeNumbers;
}
public void setWholeNumbers(int[] wholeNumbers) {
this.wholeNumbers = wholeNumbers;
}
public MultiThreading(int[] wholeNumbers, int threshold) {
this.wholeNumbers = wholeNumbers;
this.threshold = threshold;
}
#Override
public void run() {
if (wholeNumbers.length > threshold) {
int[] left = Arrays.copyOfRange(wholeNumbers, 0, wholeNumbers.length / 2);
int[] right = Arrays.copyOfRange(wholeNumbers, wholeNumbers.length / 2, wholeNumbers.length);
MultiThreading leftM = new MultiThreading(left, threshold);
MultiThreading rightM = new MultiThreading(right, threshold);
Thread leftThread = new Thread(leftM);
Thread rightThread = new Thread(rightM);
leftThread.start();
rightThread.start();
try {
leftThread.join();
rightThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
setWholeNumbers(Sort.merge(leftM.getWholeNumbers(), rightM.getWholeNumbers()));
}
else {
Sort.bubbleSort(wholeNumbers);
}
}
}
Here is my code in the main class:
MultiThreading multiThreading = new MultiThreading(wholeNumbers, threshold);
Thread thread = new Thread(multiThreading);
thread.start();
thread.join();
wholeNumbers = multiThreading.getWholeNumbers();
I should learn to use a pen and paper, understand the logic and then code.
Thanks for the comments.
Related
I wrote the below code trying to run two threads for calling a function in a for loop, but the results have the same time as if I ran it sequentially without multiple threads. Any thoughts why the multithreading here is not working? Is there a better way to do it? Like for example if I wanted to have 10 threads, using my code this will mean I have to create 10 duplicate run() functions when creating the thread, I wonder if there is an easier way to set the number of threads? Also is it possible to create a number of threads depending on the loop counter so that each loop a thread is created to finish it so if I had 10 loops then 10 threads will run concurrently to finish the processing very fast?
private Thread t1 = new Thread(){
public void run(){
for (int i = 0; i < 2; i++)
{
try {
myfn(i);
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
private Thread t2 = new Thread(){
public void run(){
for (int i = 2; i < 4; i++)
{
try {
myfn(i);
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
public Results getResults() throws IOException, SocketTimeoutException {
t1.start();
t2.start();
try {
t1.join(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
t2.join(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
For running the same task across multiple threads, you're probably looking for a thread pool. Java provides a ThreadPoolExecutor for this.
Here is an introduction to Java concurrency with the following example:
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(() -> {
try {
TimeUnit.SECONDS.sleep(2);
return 123;
}
catch (InterruptedException e) {
throw new IllegalStateException("task interrupted", e);
}
});
future.get(1, TimeUnit.SECONDS);
That example specifically creates a pool with only a single thread, but the parameter to Executors.newFixedThreadPool controls how many threads will be used.
I'm not sure from your original question why you think two threads aren't being utilized.
public class MyThead extend Thread{
private int initValue = 0;
private int upperBound = 0;
public MyThread(int init, int ub){
this.initValue = init;
this.upperBound = ub;
}
public void run(){
for(int i = init; i < upperBound; i++){
myfn(i);
}
}
}
Create threads and start them:
List<Thread> threads = new ArrayList<>();
threads.add(new MyThread(0,2));
threads.add(new MyThread(2,4));
for(Thread t: threads){
t.start()
}
for(Thread t: threads){
t.join();
}
I wrote the below code trying to run two threads for calling a function in a for loop, but the results have the same time as if I ran it sequentially without multiple threads.
There are many reasons why that can happen although it's hard to know what is going on without seeing the myfn(...) code. Here are some possible reasons:
It could be that myfn runs so quickly that running it in different threads isn't going to be any faster.
It could be that myfn is waiting on some other resource in which case the threads can't really run concurrently.
It could be that myfn is blocking on IO (network or disk) and even though you are doing 2 (or more) of them at a time, the disk or the remote server can't handle the increased requests any faster.
Is there a better way to do it? Like for example if I wanted to have 10 threads, using my code this will mean I have to create 10 duplicate run() functions...
The right thing to do here is to create your own class which takes the lower and upper bounds. The right way to do this is to implement Runnable, not extend Thread. Something like:
public class MyRunnable implements Runnable {
private final int start;
private final int end;
public MyRunnable(int start, int end) {
this.start = start;
this.end = end;
}
public void run() {
for (int i = start; i < end; i++) {
myfn(i);
}
}
}
You can then either start the threads by hand or use an ExecutorService which makes the thread maintenance a lot easier:
// this will start a new thread for every job
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(new MyRunnable(0, 2));
threadPool.submit(new MyRunnable(2, 4));
// once you've submitted your last task, you shutdown the pool
threadPool.shutdown();
// then we wait until all of the tasks have run
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
You don't need to copy your threads / loop 10 times, just take the logic and use it appropriately.
public class ExampleThread extends Thread {
private final int start, iterations;
public ExampleThread(int start, int iterations) {
this.start = start;
this.iterations = iterations;
}
#Override public void run() {
for (int i = 0; i < iterations; i++) {
myfn(start + i);
}
}
}
int iterations = 2;
List<Thread> threads = new ArrayList<>();
for (int threadId = 0; threadId < 10; threadId++) {
threads.add(new ExampleThread(threadId * iterations, iterations));
}
threads.forEach(Thread::start);
threads.forEach(t -> {
try {
t.join(0);
} catch (Exception e) {
e.printStackTrace(System.err);
}
});
Suppose I have the following code, where one thread generates squares and writes them to a buffer while another thread prints them:
import java.util.*;
public class Something {
public static Buffer buffer = new Buffer();
public static class Buffer {
private int[] buffer;
private static final int size = 10;
//Indexes for putting and taking element form buffer
private int in, out;
//Number of elements in buffer
private int k;
public Buffer() {
buffer = new int[size];
in = 0;
out = 0;
k = 0;
}
public synchronized void put(int e) {
try {
while (k == buffer.length) {
wait();
}
} catch (InterruptedException ex) {
}
buffer[in] = e;
k++;
in = ++in % size;
notifyAll();
}
public synchronized int take() {
try {
while (k == 0) {
wait();
}
} catch (InterruptedException ex) {
}
int e = buffer[out];
buffer[out] = 0;
out = ++out % size;
k--;
notifyAll();
return e;
}
public synchronized boolean notEmpty() {
return k != 0;
}
}
public static class Generator implements Runnable {
int limit;
public Generator(int lim) {
limit= lim;
}
#Override
public void run() {
for (int i = 1; i < limit; i++) {
buffer.put(i * i);
}
}
}
public static class Printer implements Runnable {
private Thread[] generators;
public Printer(Thread[] gen) {
generators = gen;
}
public synchronized boolean nobody() {
for (Thread th : generators) {
if (th.isAlive()) {
return false;
}
}
return true;
}
#Override
public void run() {
int x = 0;
while (!nobody() || buffer.notEmpty()) {
x = buffer.take();
System.out.println(x);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread generator = new Thread(new Generator(69));
Thread printer = new Thread(new Printer(new Thread[]{generator}));
generator.start();
printer.start();
generator.join();
printer.join();
}
}
Generator should generate squares of numbers until it reaches some limit (limit = 69, in this case). Printer should print all values generated by Generator. Buffer works somewhat like ring buffer. Indexes for putting (in) and taking (out) element are cycling in bounds of buffer size. Buffer has methods for putting and taking elements from buffer. Generator thread cannot put elements in buffer if it is full (that is, there are no zero elements; zero element is 0, for precision sake...). Printer works this way: first it checks if there are any alive generator threads and then checks if buffer contains only zero elements. If neither of these conditions is true, printer thread terminates.
Now, to the problem. I always get printed all squares from 1 to 68, which is expected output of this program. However, on very rare occasion after all numbers had been output I get a deadlock. How rarely? Well, maybe in 1 out of 100 executions of program. I had to keep hitting "F6" on NetBeans like crazy to get a deadlock. And yes, I know that I can test this simply putting all main code in for loop.
Conversely, if I comment out print line in Printers' run method, deadlock happens almost all the time. Here:
#Override
public void run() {
int x = 0;
while (!nobody() || buffer.notEmpty()) {
x = buffer.take();
//System.out.println(x);
}
}
I do not expect this behavior, because element still gets taken from buffer and generator should be awoken.
Why does this happen? And how do I fix it?
Sorry if question isn't clear enough, I'll try to clarify it as best I can if needed.
I think I fount the problem. Here is what I got: There is a very short moment in time, where the Generator thread is still alive (i.e. Thread.isAlive() will return true), but the Generator has left the for-loop within run(). If the Printer queries its while-condition within its run() at this point in time, it will try to take() something, that is not there (and never will be). Indeed, you can verify, that the Generator always finishes, meaning termination detection on the side of the Printer is faulty. For a hot fix, you can simply add a magic constant is Printers while condition:
#Override
public void run() {
int x = 0;
int count = 0;
while (++count < 69) {
x = buffer.take();
System.out.println(x);
}
}
For a clean termination detection, you could set some common flag-variable to false, signaling that the Generator has finished work and the Printer can stop working. But this has to be done in a synchronized manner, meaning the Printer is not allowed to query this condition, while the Generator is after its last push, but before it sets this common flag.
On compiling my code below it seems to be in a state of deadlock, and i don't know how i can fix it. I am attempting to write a pipeline as a sequence of threads linked together as a buffer, and each thread can read the preceding node in the pipeline, and consequentially write to the next one. The overall goal is to spilt a randomly generated arraylist of data over 10 threads and sort it.
class Buffer{
// x is the current node
private int x;
private boolean item;
private Lock lock = new ReentrantLock();
private Condition full = lock.newCondition();
private Condition empty = lock.newCondition();
public Buffer(){item = false;}
public int read(){
lock.lock();
try{
while(!item)
try{full.await();}
catch(InterruptedException e){}
item = false;
empty.signal();
return x;
}finally{lock.unlock();}
}
public void write(int k){
lock.lock();
try{
while(item)
try{empty.await();}
catch(InterruptedException e){}
x = k; item = true;
full.signal();
}finally{lock.unlock();}
}
}
class Pipeline extends Thread {
private Buffer b;
//private Sorted s;
private ArrayList<Integer> pipe; // array pipeline
private int ub; // upper bounds
private int lb; // lower bounds
public Pipeline(Buffer bf, ArrayList<Integer> p, int u, int l) {
pipe = p;ub = u;lb = l;b = bf;//s = ss;
}
public void run() {
while(lb < ub) {
if(b.read() > pipe.get(lb+1)) {
b.write(pipe.get(lb+1));
}
lb++;
}
if(lb == ub) {
// store sorted array segment
Collections.sort(pipe);
new Sorted(pipe, this.lb, this.ub);
}
}
}
class Sorted {
private volatile ArrayList<Integer> shared;
private int ub;
private int lb;
public Sorted(ArrayList<Integer> s, int u, int l) {
ub = u;lb = l;shared = s;
// merge data to array from given bounds
}
}
class Test1 {
public static void main(String[] args) {
int N = 1000000;
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=0;i<N;i++) {
int k = (int)(Math.random()*N);
list.add(k);
}
// write to buffer
Buffer b = new Buffer();
b.write(list.get(0));
//Sorted s = new Sorted();
int maxBuffer = 10;
int index[] = new int[maxBuffer+1];
Thread workers[] = new Pipeline[maxBuffer];
// Distribute data evenly over threads
for(int i=0;i<maxBuffer;i++)
index[i] = (i*N) / maxBuffer;
for(int i=0;i<maxBuffer;i++) {
// create instacen of pipeline
workers[i] = new Pipeline(b,list,index[i],index[i+1]);
workers[i].start();
}
// join threads
try {
for(int i=0;i<maxBuffer;i++) {
workers[i].join();
}
} catch(InterruptedException e) {}
boolean sorted = true;
System.out.println();
for(int i=0;i<list.size()-1;i++) {
if(list.get(i) > list.get(i+1)) {
sorted = false;
}
}
System.out.println(sorted);
}
}
When you start the run methods, all threads will block until the first thread hits full.await(). then one after the other, all threads will end up hitting full.await(). they will wait for this signal.
However the only place where full.signal occurs is after one of the read methods finishes.
As this code is never reached (because the signal is never fired) you end up with all threads waiting.
in short, only after 1 read finishes, will the writes trigger.
if you reverse the logic, you start empty, you write to the buffer (with signal, etc, etc) and then the threads try to read, I expect it will work.
generally speaking you want to write to a pipeline before reading from it. (or there's nothing to read).
I hope i'm not misreading your code but that's what I see on first scan.
Your Buffer class it flipping between read and write mode. Each read must be followed by a write, that by a read and so on.
You write the buffer initially in your main method.
Now one of your threads reaches if(b.read() > pipe.get(lb+1)) { in Pipeline#run. If that condition evaluates to false, then nothing gets written. And since every other thread must still be the very same if(b.read(), you end up with all reading threads that can't progress. You will either have to write in the else branch or allow multiple reads.
I need to run a java program called ArrayHolder that will run two Threads. ArrayHolder will have an Array. ThreadSeven will overwrite every element of that Array with 7, and ThreadOne with 1.
The result after execution should be 7,1,7,1,7,1,7,1 etc. I have solved this problem, although I dont like my solution and was hoping you could suggest a better way.
p.s: Both Threads must write on all indexes.
public class ArrayHolder {
private int[] array = {1, 2, 3, 4, 5, 6, 4, 8, 9, 10};
public void writeInt(int pos, int num) {
array[pos] = num;
}
public static void main(String[] args) {
ArrayHolder holder = new ArrayHolder();
ThreadSeven seven = new ThreadSeven(holder, null);
Runnable one = new ThreadOne(holder, seven);
Thread thread1 = new Thread(seven);
Thread thread2 = new Thread(one);
seven.setThread(one);
thread1.start();
thread2.start();
holder.printArray();
}
private void printArray() {
for (int i = 0; i < 10; i++) {
System.out.println(array[i]);
}
}
public class ThreadSeven implements Runnable {
private ArrayHolder array;
private Runnable t;
private int flag=0;
#Override
public void run() {
for(int i=0;i<10;i++){
array.writeInt(i, 7);
flag=(flag+1)%2;
if (flag==0){
synchronized(t){
t.notify();
}
}else{
synchronized(this){
try {
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(ThreadSeven.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
public ThreadSeven (ArrayHolder ar,Runnable t){
array=ar;
this.t=t;
}
public void setThread(Runnable t){
this.t=t;
}
}
public class ThreadOne implements Runnable {
private ArrayHolder array;
private Runnable t;
private int flag = 0;
#Override
public void run() {
for (int i = 0; i < 10; i++) {
array.writeInt(i, 1);
flag = (flag + 1) % 2;
if (flag == 1) {
synchronized (t) {
t.notify();
}
} else {
synchronized (this) {
try {
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(ThreadSeven.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
public ThreadOne(ArrayHolder ar, Runnable t) {
array = ar;
this.t = t;
}
public void setThread(Runnable t) {
this.t = t;
}
}
ThreadSeven and ThreadOne don't need to be separate classes; is looks like you just copy/pasted the code, and then changed the 7 in writeInt to a 1. Instead, you can paramaterize this value and pass it in the constructor. Then you get something like:
public class ThreadWriter implements Runnable {
private final int numberToWrite;
// ...
public ThreadOne(ArrayHolder ar, Runnable t, int numberToWrite) {
array = ar;
this.t = t;
this.numberToWrite = numberToWrite;
}
// ...
}
Another point is that both of your threads have to know about each other; this doesn't scale well. Pretend that for your next assignment your teacher said that you have to handle three threads which write 1, 4, 7, 1, 4, 7, ...; you would have to change the implementation of ThreadOne and ThreadSeven. A better solution which you could make now is have the ThreadWriters themselves be dumber, and manage their interaction more in the ArrayHolder class (or with an intermediary ThreadWriterManager class).
Your solution has some problems and looks to me like it would not print the correct result.
a) You don't wait for the threads to finish before you print the resulting array
Add thread1.join() and thread2.join() before holder.printArray() in case it is not there yet.
b) both threads start with writing immediately via array.writeInt(0, /* 1 or 7 */); After that they start to wait on each other. Whether the first index is correct or not depends on luck.
c) Continuing after this.wait(); without a loop checking a condition is not safe since the interrupt could be caused by something else than the other thread. I guess it's okay to do that here since it's just an exercise.
d) I see a potential deadlock: let's assume both threads are still writing the first index. So both are not in a synchronized block.
The thread that has to notify the other one does so, writes the next index and goes into it's own wait block.
But the second thread was not waiting at the time so the notify from the first thread did nothing. Second thread goes into wait block too.
Now both threads wait on each other and nothing happens anymore.
I don't have a great simple solution for you since that problem is quite complex.
The 1-thread needs to start writing at index 0 then wait until the 7-thread has written index 0 and 1, now 1-thread writes index 1 and 2 and waits and so on. That is the only way I see possible to ensure that both thread have written to every index and that the result is 7-1-7-1-.... Synchronizing access inside ArrayHolder would be very tricky since it needs to make sure that both threads have written to each index in the correct order.
But I think your general idea is okay. You just need to make sure that it is safe
I have a thread with the following form:
each execution of each thread is supposed to run a function in the class. That function is completely safe to run by itself. The function returns a value, say an int.
After all threads have been executed, the function values need to be accumulated.
So, it goes (in pseudo-code) something like that:
a = 0
for each i between 1 to N
spawn a thread independently and call the command v = f(i)
when thread finishes, do safely: a = a + v
end
I am not sure how to use Java in that case.
The problem is not creating the thread, I know this can be done using
new Thread() {
public void run() {
...
}
}
the problem is accumulating all the answers.
Thanks for any info.
I would probably do something like:
public class Main {
int a = 0;
int[] values;
int[] results;
public Main() {
// Init values array
results = new int[N];
}
public int doStuff() {
LinkedList<Thread> threads = new LinkedList<Thread>();
for (final int i : values) {
Thread t = new Thread() {
public void run() {
accumulate(foo(i));
}
};
threads.add(t);
t.start();
}
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
// Act accordingly, maybe ignore?
}
}
return a;
}
synchronized void accumulate(int v) {
// Synchronized because a += v is actually
// tmp = a + v;
// a = tmp;
// which can cause a race condition AFAIK
a += v;
}
}
Use an ExecutorCompletionService, Executor, and Callable.:
Start with a Callable that calls your int function:
public class MyCallable implements Callable<Integer> {
private final int i;
public MyCallable(int i) {
this.i = i;
}
public Integer call() {
return Integer.valueOf(myFunction(i));
}
}
Create an Executor:
private final Executor executor = Executors.newFixedThreadPool(10);
10 is the maximum number of threads to execute at once.
Then wrap it in an ExecutorCompletionService and submit your jobs:
CompletionService<Integer> compService = new ExecutionCompletionService<Integer>(executor);
// Make sure to track the number of jobs you submit
int jobCount;
for (int i = 0; i < n; i++) {
compService.submit(new MyCallable(i));
jobCount++;
}
// Get the results
int a = 0;
for (int i = 0; i < jobCount; i++) {
a += compService.take().get().intValue();
}
ExecutorCompletionService allows you to pull tasks off of a queue as they complete. This is a little different from joining threads. Although the overall outcome is the same, if you want to update a UI as the threads complete, you won't know what order the threads are going to complete using a join. That last for loop could be like this:
for (int i = 0; i < jobCount; i++) {
a += compService.take().get().intValue();
updateUi(a);
}
And this will update the UI as tasks complete. Using a Thread.join won't necessarily do this since you'll be getting the results in the order that you call the joins, not the order that the threads complete.
Through the use of the executor, this will also allow you to limit the number of simultaneous jobs you're running at a given time so you don't accidentally thread-bomb your system.