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.
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
I am testing the use of semaphores with the typical producer-consumer problem where I only have one producer and one consumer. The producer adds products one at a time and the consumer can withdraw several simultaneously.
To perform the test, the producer and the consumer store and remove numbers from a array of 10 elements where 0 represents that there are no products and any other number represents a product. Access to store and retrieve items is centralized in a class called Data. I use a mutex to make an orderly use of the vector in case we have more than one thread working simultaneously.
When executing it, I observe that the number of permissions is not correct according to the operations performed by the threads. The application shows an error because the semaphore of the producer says that it has permission, but the data vector is full.
package producer.consumer;
import java.io.IOException;
public class ProducerConsumer {
public static void main(String[] args) throws IOException {
final int MAX = 10;
Data data = new Data(MAX);
Consumer consumer = new Consumer(data);
Producer producer = new Producer(data);
consumer.start();
producer.start();
}
}
package producer.consumer;
public class Producer extends Thread{
private final Data data;
public Producer(Data data) {
this.data = data;
}
#Override
public void run() {
while (true) {
try {
data.add((int) (Math.random() * data.getLength()) + 1);
} catch (InterruptedException ex) {
System.out.println(ex.getMessage());
}
}
}
}
package producer.consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Consumer extends Thread{
private final Data data;
public Consumer(Data data) {
this.data = data;
}
#Override
public void run() {
while (true) {
try {
data.remove((int) (Math.random() * data.getLength()) + 1);
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
package producer.consumer;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
public class Data {
private final int[] data;
private final Semaphore mutex = new Semaphore(1);
private final Semaphore semProducer, semConsumer;
public Data(int MAX) throws IOException {
data = new int[MAX];
semProducer = new Semaphore(MAX);
semConsumer = new Semaphore(0);
}
public int getLength() {
return data.length;
}
public void add(int number) throws InterruptedException {
semProducer.acquire();
mutex.acquire();
System.out.println("trying to add a product");
int i = 0;
while (data[i] != 0) {
i++;
}
data[i] = number;
int permits = semConsumer.availablePermits() + 1;
System.out.println("data added in " + i + " " + Arrays.toString(data)
+ " Resources consumer " + permits
+ " Resources producer " + semProducer.availablePermits());
mutex.release();
semConsumer.release();
}
public void remove(int numberElements) throws InterruptedException {
semConsumer.acquire(numberElements);
mutex.acquire();
System.out.println("trying to withdraw " + numberElements);
for (int i = 0; i < numberElements; i++) {
if (data[i] != 0) {
data[i] = 0;
}
}
int permisos = semProducer.availablePermits() + 1;
System.out.println(" Retired " + numberElements + " " + Arrays.toString(data)
+ " Resources consumer " + semConsumer.availablePermits()
+ " Resources producer " + permisos);
mutex.release();
semProducer.release(numberElements);
}
}
Thank you very much for the help.
Your consumer does not always consume what it claims to consume.
for (int i = 0; i < numberElements; i++) {
if (data[i] != 0) {
data[i] = 0;
}
}
Suppose numberElements is 3, and that we have exactly 3 available elements in data[7], data[8], data[9].
The loop terminates with i == 3, nothing has been removed, but the producer semaphore will still be 'upped' by 3.
In the consumer, if you use i as the array index, it needs to cover the whole array, and you need a separate counter for 'elements removed'.
It is not the case that available elements will always be in the lowest-numbered data slots even though the producer fills those in first. Consider the time sequence that the producer manages to produce at least 5 elements, then the consumer runs to consume 2, and then immediately runs again to consume 3, before any more have been produced. data[0] and data[1] will be empty on the second run of the consumer and we run into the scenario I describe.
EDIT Acquiring and releasing permits seems correct; but you need to make sure that the consumer will actually clear the correct number of elements.
In example, edit the Data class with
public void remove(int numberElements) throws InterruptedException {
semConsumer.acquire(numberElements);
mutex.acquire();
System.out.println("remove: num-elem=" + numberElements);
int consumed=0;
for (int i = 0; consumed<numberElements; i++) {
if (data[i] != 0) {
data[i] = 0;
consumed++;
}
}
System.out.println(
" Retired " + numberElements + " " + Arrays.toString(data) );
mutex.release();
semProducer.release(numberElements);
}
Note also that this implementation is not very efficient (you'll need to iterate over the whole array both when inserting and deleting items, which can be expensive when MAX is large..)
I'm trying to build simple multithreading application. But I'm confused about Java monitors. I have many threads that want to format with their data one array. So for example I have Supermarket Threads (data of the thread is in txt file) So first thread have these product (Milk, Cheese, Chocolate) and country code for each product 1,2, 3
SupermarketA
Milk 1
Cheese 2
Chocolate 3
SupermarketB
Yogurt 1
Orangle 2
Bannana 3
Tea 7
Kiwi 9
and I want to format array that has to fields (country_code and count)
So my array should look like that
Country_code count
1 2
2 2
3 2
7 1
9 1
Code
public class SortedArray{
private int num = 0; // num is country code
private int count = 0;
}
So here's my monitor class
public class SingleArray {
private SortedArray[] array;
private int arrayIndex;
private static final int MAX_SIZE = 5;
public SingleArray() {
array = new SortedArray[MAX_SIZE];
arrayIndex = 0;
initArray();
}
private void initArray() {
for (int i = 0; i < MAX_SIZE; i++) {
array[i] = new SortedArray();
}
}
public synchronized void inc(){
awaitUnderMax();
notifyAll();
}
private void awaitUnderMin(){
while (arrayIndex == 0) try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void dec(){
awaitUnderMin();
notifyAll();
}
public void add(ArrayList<Integer> count){
for (int i = 0; i < count.size(); i++) {
singleArray.inc();
int num = count.get(i);
if (singleArray.arrayIndex == 0) { // if array is empty add value to it
singleArray.array[0].num = num;
singleArray.array[0].count++;
singleArray.arrayIndex++;
} else {
if (!isThere(num)) { // if num is a new value to array
singleArray.inc();
int index1 = singleArray.arrayIndex;
if (num > singleArray.array[index1 - 1].num) {
singleArray.inc();
singleArray.array[index1].num = num;
singleArray.inc();
singleArray.array[index1].count++;
singleArray.inc();
singleArray.arrayIndex++;
System.out.println(Thread.currentThread().getName() + " first " + singleArray.array[index1].num);
} else if (num < singleArray.array[index1 - 1].num) { // jei num mazesne uz paskutinia masyvo reiksme
int index = index1 - 1 < 0 ? index1 : index1 - 1;
while (index > 0 && num < singleArray.array[index].num) {
index--;
}
if (index != singleArray.arrayIndex) {
System.out.println(Thread.currentThread().getName() + " sec " + singleArray.array[index].num);
singleArray.array = addPos(singleArray.array, index + 1, num);
}
}
}
}
}
}
public boolean isThere(int number){
for(int i=0; i<singleArray.arrayIndex; i++){
singleArray.inc();
if(number == singleArray.array[i].num){
singleArray.array[i].count++;
return true;
}
}
return false;
}
private void awaitUnderMax(){
while (arrayIndex >= MAX_SIZE) try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void removeValue(int number, int howManyItems){
for(int i=0; i<arrayIndex; i++){
dec();
if(number == array[i].num){
int numberToDelete = array[i].count - howManyItems >= 0 ? howManyItems : array[i].count;
if(array[i].count >= numberToDelete){
array[i].count -= numberToDelete;
}
if(array[i].count == 0){
deleteItem(i);
}
}
if(array[i].count == 0){
deleteItem(i);
}
}
}
Each thread call add(ArrayList<Integer> count) method
So basically what add method does:
Find place where to insert new value (dependng if new value is greater or lower than a previous)
call isThere(int num) method that check if new value is already in array (if so increment count singleArray.array[i].count++) otherwise add new value to array
If array is full arrayIndex == MAX_SIZE wait current thread for other threads to decrement arrayIndex (this is oly one part of code I also have other threads that based on county code decrement array)
So the biggest problem is that multiplethreads need to update single array at the same time (I know that adding synchronized keyword to add method should solve this problem but it only let one thread to run this method at once!) So sometimes all works fine, but sometimes I get really starnge results (for example that country code is 0 (That is imposible!!!) and sometimes new values is placed in wrong array posiitons). Also I think that semaphores should solve this problem, but is it possible to do that with monitors? Thank's for the answers.
EDIT v2
to #Elyasin
public Thread[] setUpShopsBuilderThreads(){
int size = data.getSize();
ArrayList<ArrayList<String>> a = new ArrayList<>();
ArrayList<ArrayList<Integer>> b = new ArrayList<>();
ArrayList<ArrayList<Double>> c = new ArrayList<>();
Thread[] threads = new Thread[size];
for (int i = 0; i < size; i++) {
int tmp = data.getIndex(i);
int range = i + 1 < size ? data.getIndex(i + 1) : data.getWaresSize();
ArrayList<String> name = new ArrayList<>();
ArrayList<Integer> count = new ArrayList<>();
ArrayList<Double> price = new ArrayList<>();
for (int j = tmp; j < range; j++) {
name.add(data.getName(j));
count.add(data.getCount(j));
price.add(data.getPrice(j));
}
a.add(name);
b.add(count);
c.add(price);
}
procesas_1 p1 = new procesas_1(a.get(0), b.get(0), c.get(0));
procesas_2 p2 = new procesas_2(a.get(1), b.get(1), c.get(1));
procesas_3 p3 = new procesas_3(a.get(2), b.get(2), c.get(2));
procesas_4 p4 = new procesas_4(a.get(3), b.get(3), c.get(3));
procesas_5 p5 = new procesas_5(a.get(4), b.get(4), c.get(4));
Thread worker1 = new Thread(p1);
Thread worker2 = new Thread(p2);
Thread worker3 = new Thread(p3);
Thread worker4 = new Thread(p4);
Thread worker5 = new Thread(p5);
threads[0] = worker1;
threads[1] = worker2;
threads[2] = worker3;
threads[3] = worker4;
threads[4] = worker5;
return threads;
}
public static void main(String[] args) {
Starter start = new Starter();
start.read();
start.printShopsData();
start.printUserData();
Thread[] builderThreads = start.setUpShopsBuilderThreads();
for(int i=0; i<builderThreads.length; i++){
builderThreads[i].start();
}
}
what about using the concurrent safe datasets java already provides?
if you want it sorted, this one looks it might work for you:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentSkipListSet.html
just add it as in a normal Collection
Currently when I run the program, the threads are running at random. For example the current output is :
Global.sharedBuffer[0] = 2
Global.sharedBuffer[1] = 1
Global.sharedBuffer[2] = 1
Global.sharedBuffer[3] = 1
Global.sharedBuffer[4] = 1
Global.sharedBuffer[5] = 1
Global.sharedBuffer[6] = 1
Global.sharedBuffer[7] = 1
Global.sharedBuffer[8] = 1
Global.sharedBuffer[9] = 1
Global.sharedBuffer[10] = 2
Global.sharedBuffer[11] = 4
Global.sharedBuffer[12] = 3
What I want is from sharedBuffer 0 to 9 all 1's , then from 10 - 19 all 2's and etc. I added a synchronization block thinking it would do this, however, it just stopped it from context switching every time a thread was called. How do you go about implementing this?
CODE:
import java.io.*;
import java.lang.*;
import java.util.*;
class MyThreadExample2 {
public static void main(String[] args) {
HelloThread ht1 = new HelloThread(1);
HelloThread ht2 = new HelloThread(2);
HelloThread ht3 = new HelloThread(3);
HelloThread ht4 = new HelloThread(4);
ht1.start();
ht2.start();
ht3.start();
ht4.start();
}
}
class Global {
public static int[] sharedBuffer = new int[1000];
public static int in = 0;
}
class HelloThread extends Thread {
int threadID;
HelloThread(int threadID) {
System.out.println("threadID: " + threadID);
this.threadID = threadID;
}
public synchronized void run() {
for (int i = 0; i < 100; i++) {
if((Global.in >= 0 || Global.in <= 99) && (this.threadID == 1))
Global.sharedBuffer[Global.in] = this.threadID;
else if((Global.in >= 100 || Global.in <= 199) && (this.threadID == 2))
Global.sharedBuffer[Global.in] = this.threadID;
else if((Global.in >= 200 || Global.in <= 299) && (this.threadID == 3))
Global.sharedBuffer[Global.in] = this.threadID;
else if((Global.in >= 300 || Global.in <= 399) && (this.threadID == 4))
Global.sharedBuffer[Global.in] = this.threadID;
System.out.println("Thread " + this.threadID + " has written "
+ this.threadID + " to Global.sharedBuffer[" + Global.in + "]\n");
Global.in++;
}
if (this.threadID == 4)
{
try {this.sleep(2000L);
}
catch (Throwable e) {e.printStackTrace();
}
System.out.println("The final buffer is **************\n");
for (int i = 0; i < 30; i++) {
System.out.println("Global.sharedBuffer[" + i + "] = " +
Global.sharedBuffer[i]);
} // for
} // if
} // run
} // end Thread
Multi-threading only works if you can formulate tasks which can be performed independently of others. You have to avoid shared variables and if you can’t avoid it, the access must be properly guarded, which usually implies limiting the concurrency of the thread execution.
For your task it is simple to formulate independent tasks as each thread shall write into a different region of the array:
public class ThreadingExample {
public static void main(String[] args) {
final int numThread=4, chunkSize=10;
int[] array=new int[numThread*chunkSize];
Thread[] thread=new Thread[numThread];
// create threads and define their jobs
for(int t=0, p=0; t<numThread; t++, p+=chunkSize) {
thread[t]=new Thread(new FillInJob(array, t, p, chunkSize));
}
// start the threads
for(Thread t: thread) t.start();
// now all running concurrently
// wait for completion
try {
for(Thread t: thread) t.join();
} catch(InterruptedException ex) {
throw new AssertionError(ex);
}
// use result
System.out.println(java.util.Arrays.toString(array));
}
}
class FillInJob implements Runnable {
private final int[] targetArray;
private final int myID, startIndex, endIndex;
FillInJob(int[] target, int id, int start, int size) {
targetArray=target;
myID=id;
startIndex=start;
endIndex=start+size;
}
public void run() {
for(int ix=startIndex; ix<endIndex; ix++)
targetArray[ix]=myID;
}
}
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");
}
}