I am writing code to let 4 threads build a histogram.
I have an array in main:
int N = 10000;
Random r = new Random();
int[] a = new int[N];
for (int i = 0; i < a.length; i++)
{
a[i] = Math.abs(r.nextInt() % 100);
}
So basically what I want to do is cycle through this array and count how many times each number appears.
So I have written my thread class, and I used AtomicInteger which I thought would help solve the problem of multiple threads trying to access the same index simultaneously.
import java.util.concurrent.atomic.AtomicInteger;
public class UseThread implements Runnable
{
private static int[] array;
private static AtomicInteger[] count;
private static boolean[] check;
public UseThread(int[] array, AtomicInteger[] count)
{
this.array = array;
this.count = count;
this.check = new boolean[array.length];
}
public void run()
{
for (int i = 0; i < array.length; i++)
{
if (!getIndex(this.check[i]))
{
this.check[i] = true;
int number = array[i];
count[number].incrementAndGet();
}
}
}
public synchronized static boolean getIndex(boolean check2)
{
return check2;
}
However, this hasn't quite fixed my problem. Some of the threads are accessing the array at the same time, making the count array, hold a larger value than the length of the array array.
I think the problem is in the boolean array of checking. I have a feeling that multiple threads access the same boolean array index at the same time.
I figure it is probably a simple fix, but I am just not seeing it.
Any suggestions??
I have tried the AtomicBoolean array, but it has not helped. Below is the same class but with the AtomicBoolean array implemented.
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class Assign7Q3 implements Runnable
{
private static int[] array;
private static AtomicInteger[] count;
private static AtomicBoolean[] check;
public Assign7Q3(int[] array, AtomicInteger[] count)
{
this.array = array;
this.count = count;
this.check = new AtomicBoolean[array.length];
for(int i = 0; i < check.length; i ++)
check[i] = new AtomicBoolean(false);
}
public void run()
{
for (int i = 0; i < array.length; i++)
{
//System.out.println(this.check[i].get());
if (!getIndex(this.check[i]))
{
this.check[i].set(true);
int number = array[i];
count[number].incrementAndGet();
}
}
}
public synchronized static boolean getIndex(AtomicBoolean check2)
{
return check2.get();
}
You need to use compareAndSet for your if statement to be mutally exclusive:
if (this.check[i].compareAndSet(false, true))
{
int number = array[i];
count[number].incrementAndGet();
}
This both checks and sets the value atomically.
Without compareAndSet, there is a possibility that two threads can check the value and enter the if block at the same time before one has a chance to call set(true).
Related
The followiing code uses threads to calculate the max value in a subarry, and then calculates the max value out of the max values the threads returned. I have a bug that the main thread doesn't wait for the threads to finish when collecting the results.
Thread class:
public class MaxTask extends Thread {
private int[] arr;
private int max;
private int first, last;
public MaxTask(int[] arr, int first, int last) {
this.arr = arr;
this.first = first;
this.last = last;
}
public int getMax() {
return max;
}
public void run() {
max = arr[first];
for (int i = first + 1; i <= last; i++) {
if (arr[i] > max) max = arr[i];
}
}
}
Main:
public class MainMax {
public static void main(String[] args) throws Exception {
int size = 100;
int workers = 10;
int[] arr = new int[size];
int max = 0;
for (int i = 0; i < size; i++) {
arr[i] = (int)(Math.random() * 100);
if (max < arr[i]) max = arr[i];
}
System.out.println("max=" + max);
int gsize = (arr.length - 1) / workers;
MaxTask[] tasks = new MaxTask[workers];
int first = 0;
int last;
for (int i = 0; i < workers; i++) {
last = first + gsize;
tasks[i] = new MaxTask(arr, first, last);
tasks[i].start();
first = last + 1;
}
int maxmax = tasks[0].getMax();
int temp;
for (int i = 1; i < workers; i++) {
temp = tasks[i].getMax();
if (temp > maxmax) maxmax = temp;
}
System.out.println("maxmax=" + maxmax);
}
}
I am trying to solve the problem using synchronized. I managed to get it working when using synchronized on both run and getMax. But I really don't understand why this solves the problem.
First, you must understand that the main class is also running on a thread. That thread is seperate from the threads you created for the function and is thus running in parallel to them. By that logic, int maxmax = tasks[0].getMax(); is running asynchronously and possibly before the loop is finished.
One possible solution would be to lock that part of the code and force the execution to wait before executing that line. Only release the lock after everyone in the loop is done. Synchronizing access to the run method only defeats the purpose of running multiple threads since you're forcing the whole thing to be sequential.
It is also not recommended to create a thread for every single element, since there's a tradeoff between number of threads and how much you're speeding up execution.
I'm getting a NullPointerException, it seems the program can't find nums (the array)
The Class:
/**
*Author: Chris Cherian
*Date: 4/30/14
*Desc: This program organizes numbers into 3 arrays - Even, Odd, and Negative.
*/
public class IntegerArray
{
/**
*The array that holds all the numbers.
*/
int nums [];
/**
*Holds count of the odds.
*/
private int oddCount = 0;
/**
*The numbers in the array.
*/
private int length;
/**
*Holds count of the positives.
*/
private int posCount;
public IntegerArray(int[] array)
{
nums = array;
}
/**
*The nuber of elements in the array.
*/
private final int TOTALNUMS = nums.length;
/**
*The array that holds all the even numbers.
*/
private int[] evens = new int[TOTALNUMS - this.getOddCount()];
/**
*The array that holds all the odd numbers.
*/
private int[] odds = new int[this.getOddCount()];
/**
*The array that holds all the negative numbers.
*/
private int[] negs = new int[TOTALNUMS - this.getPosCount()];
int evenCounter = 0;
/**
*Gathers the total number of odds
*#return The number of odd numbers
*/
public int getOddCount()
{
for(int i = 0; i <= TOTALNUMS; i++)
{
if(nums[i]%2 != 0)
{
oddCount++;
}
}
return oddCount;
}
/**
*Gathers number of positives
*#return posCount The number of positive numbers
*/
public int getPosCount()
{
for(int i = 0; i <= TOTALNUMS; i++)
{
if(nums[i] > 0)
{
posCount++;
}
}
return posCount;
}
public int[] organizeEvens()
{
for(int i = 0; i < nums.length; i++)
{
if(nums[i]%2 == 0)
{
evens[evenCounter] = nums[i];
evenCounter++;
}
}
return evens;
}
int oddCounter = 0;
public int[] organizeOdds()
{
for(int i = 0; i < nums.length; i++)
{
if(nums[i]%2 != 0)
{
odds[evenCounter] = nums[i];
oddCounter++;
}
}
return odds;
}
int negCounter = 0;
public int[] organizeNegs()
{
for(int i = 0; i < nums.length; i++)
{
if(nums[i]%2 == 0)
{
negs[negCounter] = nums[i];
negCounter++;
}
}
return negs;
}
}
The Client:
import java.util.Scanner;
public class IntegerArrayClient
{
public static void main(String[] jackofspades)
{
Die die1 = new Die(200);
Scanner keyboard = new Scanner(System.in);
System.out.println("How many numbers would you like to organize?");
int numbers = keyboard.nextInt();
int[] numbersarray = new int[numbers];
for(int i = 0; i < numbers; i++)
{
numbersarray[i] = (die1.Roll() - 200);
}
IntegerArray numholder = new IntegerArray(numbersarray);
int evenCount = (numbersarray.length - numholder.getOddCount());
for(int i = 0; i < evenCount; i++)
{
System.out.println(numholder.organizeEvens() + "\t");
}
}
}
The error message I get:
Exception in thread "main" java.lang.NullPointerException
at IntegerArray.<init>(IntegerArray.java:37)
at IntegerArrayClient.main(IntegerArrayClient.java:20)
The problem is that your code has an assumption that
private final int TOTALNUMS = nums.length;
would execute after the constructor, because textually it follows it. That is an incorrect assumption - this line executes before the constructor, at the time nums is still null. This is what is causing the exception.
To fix this problem, move the initialization of TOTALNUMS into the constructor:
private final int TOTALNUMS; // It's OK to leave it final - you are allowed to set it in the constructor
...
public IntegerArray(int[] array) {
nums = array;
TOTALNUMS = nums.length; // If nums is set to a non-null array, this would not cause an exception
}
Finally, note that there is little point in keeping a separate final variable for the length of nums, because its length is always available to you, and you do not need to "synchronize" the two if you decide to set nums to a different array later on.
This peice of code
private final int TOTALNUMS = nums.length;
is happening before nums has been initialized, it is still int nums []; - it has no size.
I assume that line 37 is this one:
private final int TOTALNUMS = nums.length;
The problem is that nums has not been initialized at that point, and it therefore still has its default initial value. Therefore, executing num.length throws an NPE.
How so?
Well you are initializing nums in the constructor. Bur the code in the constructor body is only executed AFTER the initializers for the instance variables have all been executed.
You need to initialize TOTALNUMS, evens, odds and so on in the constructor, since they all depend on the value passed in the constructor's array parameter.
You need to lookup up member initializers and when they run in relation to the constructor. They run before the constructor. Only after that (during the constructor) are you initializing num, and that is after you've tried to use num.Length.
Move the code that depends on nums.length to the constructor, after you've assigned nums, or in a method that is called after the object is fully created (ie. don't to it in the constructor at all, add another method on the class that returns the length).
Trying to do too much in the initializers is causing trouble.
See the first answer in this question:
Java Static Initialization Order
Or the Java rules on initialization order:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2
All these lines of code are wrong because these lines are executed as the object is created, prior to the constructor that initializes nums.
private final int TOTALNUMS = nums.length;
private int[] evens = new int[TOTALNUMS - this.getOddCount()];
private int[] odds = new int[this.getOddCount()];
private int[] negs = new int[TOTALNUMS - this.getPosCount()];
I suggest converting "evens" to "getEvens()" and calling getEvens() from main, not from the initializer.
Same for each of the other fields, convert to methods that are called later.
Suppose I have the following setup:
int[] vectorUsedForSorting = new int[] { 1,0,2,6,3,4,5 }
int[] vectorToBeSorted = new int[] {1,2,3,4,5,6,7}
What is the most efficient/fast way to sort vectorToBeSorted by using vectorUsedForSorting? For example, I would want vectorToBeSorted[0] to become vectorToBeSorted[1], since the first element of vectorUsedForSorting is 1 (i.e., vectorToBeSorted[0] should become `vectorToBeSorted[vectorUsedForSorting[0]], etc).
I am aiming for vectorToBeSorted to be [2,1,3,5,6,7,4] after the sorting algorithm is complete.
I am hoping to achieve something very fast. Note that computational complexity should be the main focus, since I will be sorting arrays of size 1,000,000 and more.
I am aiming for sub-linear time complexity if this is possible.
There are two ways to attack this. The first one is to copy a fast sort algorithm and change the access and swap-values parts with something that can handle the indirection you have:
int valueAt(int index) { return vectorUsedForSorting[index]; }
int swap(int i1, int i2) {
int tmp = vectorUsedForSorting[i1];
vectorUsedForSorting[i1] = vectorUsedForSorting[i2];
vectorUsedForSorting[i2] = tmp;
tmp = vectorToBeSorted[i1];
vectorToBeSorted[i1] = vectorToBeSorted[i2];
vectorToBeSorted[i2] = tmp;
}
The second approach is to copy the values into a new object:
public class Item {
int index;
int value;
}
Create an array of those and populate it with Items created with the values from both arrays. You can then create a Comparator<Item> which compares them by index.
When you have this, you can sort the array with Arrays.sort(items, comparator).
If that's not fast enough, then you can create N threads and have each thread sort 1/N-th of the original array. When that's done, you use the merge step from merge sort to join the results.
When performance is an issue, and the arrays are large, you at least have to consider a parallel implementation (especially since this problem is embarassingly parallel: It's not much effort and should yield a nice, near-linear speedup with an increasing number of cores) :
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ArrayReordering
{
public static void main(String[] args)
{
basicTest();
performanceTest();
}
private static void basicTest()
{
int[] vectorUsedForSorting = new int[] { 1,0,2,6,3,4,5 };
int[] vectorToBeSorted = new int[] {1,2,3,4,5,6,7};
int[] sortedVectorLinear = new int[vectorToBeSorted.length];
int[] sortedVectorParallel = new int[vectorToBeSorted.length];
sortLinear(vectorUsedForSorting, vectorToBeSorted, sortedVectorLinear);
sortParallel(vectorUsedForSorting, vectorToBeSorted, sortedVectorParallel);
System.out.println("Result Linear "+Arrays.toString(sortedVectorLinear));
System.out.println("Result Parallel "+Arrays.toString(sortedVectorParallel));
}
private static void performanceTest()
{
for (int n=1000000; n<=50000000; n*=2)
{
System.out.println("Run with "+n+" elements");
System.out.println("Creating input data");
int vectorUsedForSorting[] = createVectorUsedForSorting(n);
int vectorToBeSorted[] = new int[n];
for (int i=0; i<n; i++)
{
vectorToBeSorted[i] = i;
}
int[] sortedVectorLinear = new int[vectorToBeSorted.length];
int[] sortedVectorParallel = new int[vectorToBeSorted.length];
long before = 0;
long after = 0;
System.out.println("Running linear");
before = System.nanoTime();
sortLinear(vectorUsedForSorting, vectorToBeSorted, sortedVectorLinear);
after = System.nanoTime();
System.out.println("Duration linear "+(after-before)/1e6+" ms");
System.out.println("Running parallel");
before = System.nanoTime();
sortParallel(vectorUsedForSorting, vectorToBeSorted, sortedVectorParallel);
after = System.nanoTime();
System.out.println("Duration parallel "+(after-before)/1e6+" ms");
//System.out.println("Result Linear "+Arrays.toString(sortedVectorLinear));
//System.out.println("Result Parallel "+Arrays.toString(sortedVectorParallel));
System.out.println("Passed linear? "+
Arrays.equals(vectorUsedForSorting, sortedVectorLinear));
System.out.println("Passed parallel? "+
Arrays.equals(vectorUsedForSorting, sortedVectorParallel));
}
}
private static int[] createVectorUsedForSorting(int n)
{
// Not very elegant, just for a quick test...
List<Integer> indices = new ArrayList<Integer>();
for (int i=0; i<n; i++)
{
indices.add(i);
}
Collections.shuffle(indices);
int vectorUsedForSorting[] = new int[n];
for (int i=0; i<n; i++)
{
vectorUsedForSorting[i] = indices.get(i);
}
return vectorUsedForSorting;
}
private static void sortLinear(
int vectorUsedForSorting[], int vectorToBeSorted[],
int sortedVector[])
{
sortLinear(vectorUsedForSorting, vectorToBeSorted,
sortedVector, 0, vectorToBeSorted.length);
}
static void sortParallel(
final int vectorUsedForSorting[], final int vectorToBeSorted[],
final int sortedVector[])
{
int numProcessors = Runtime.getRuntime().availableProcessors();
int chunkSize = (int)Math.ceil((double)vectorToBeSorted.length / numProcessors);
List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
ExecutorService executor = Executors.newFixedThreadPool(numProcessors);
for (int i=0; i<numProcessors; i++)
{
final int min = i * chunkSize;
final int max = Math.min(vectorToBeSorted.length, min + chunkSize);
Runnable task = new Runnable()
{
#Override
public void run()
{
sortLinear(vectorUsedForSorting, vectorToBeSorted,
sortedVector, min, max);
}
};
tasks.add(Executors.callable(task));
}
try
{
executor.invokeAll(tasks);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
executor.shutdown();
}
private static void sortLinear(
int vectorUsedForSorting[], int vectorToBeSorted[],
int sortedVector[], int min, int max)
{
for (int i = min; i < max; i++)
{
sortedVector[i] = vectorToBeSorted[vectorUsedForSorting[i]];
}
}
}
You could create a new array, perform the sorting on that array and set vectorToBeSorted to be the new array.
int size = vectorToBeSorted.length;
int[] array = new int[size];
for (int i = 0; i < size; ++i)
array[vectorUsedForSorting[i]] = vectorToBeSorted[i];
vectorToBeSorted = array;
EDIT
If you wanted to be able to sort in place, you would need to loop through, swapping the appropriate values.
int size = vectorToBeSorted.length;
for (int i = 0; i < size; ++i) {
int index = vectorUsedForSorting[i];
int value = vectorToBeSorted[index];
vectorUsedForSorting[i] = vectorUsedForSorting[index];
vectorToBeSorted[index] = vectorToBeSorted[i];
vectorUsedForSorting[index] = index;
vectorToBeSorted[i] = value;
}
If you are able to create a pair structure that compares on indexes. You could use a sort; however, sorts are definitely slower than a linear solution.
In this case, these two statements are equivalent.
array[vectorUsedForSorting[i]] = vectorToBeSorted[i];
array[i] = vectorToBeSorted[vectorUsedForSorting[i]];
How about:
int size = size(vectorUsedForSorting);
int [] sortedVector = new int[size];
for (int i = 0; i < size; ++i)
{
sortedVector[i] = vectorToBeSorted[vectorUsedForSorting[i]];
}
Or does it have to be in place sorting?
I'm writing a program that generates a lot of random numbers. I used to set a fixed seed at the beginning to keep results replicable. The problem that I am facing now is that in a naive implementation I lose the pseudorandomity due to concurrency.
My question is this: Is it possible to preserve pseudorandomity without having inter-thread communication and if so, how?
The following code should illustrate my problem. Each run, the program returns a different triple of sums. Obviously, the order of access will also differ most of the time.
public class PseudorandomConcurrency {
private static Random rng;
private static int numDraws = 2;
private static int numThread = 3;
private static int numRuns = 3;
private static int order;
public static class Generator implements Runnable{
private static synchronized void incOrder(){
order++;
}
private static synchronized int getOrder(){
return order;
}
#Override
public void run() {
int sum = 0;
ArrayList<Integer> order = new ArrayList<Integer>();
for (int j = 0; j < numDraws; j++) {
incOrder();
order.add(getOrder());
sum += rng.nextInt(10);
}
System.out.println(sum+" order: "+order.toString());
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < numRuns; i++) {
order=0;
System.out.println("#####");
rng = new Random(1);
ArrayList<Thread> threads= new ArrayList<Thread>();
for (int j = 0; j < numThread; j++) {
threads.add(new Thread(new Generator()));
}
for (Thread thread : threads) {
thread.start();
}
Thread.sleep(1000);
}
}
}
My question is this: Is it possible to preserve pseudorandomity without having inter-thread communication and if so, how?
Yes it is. Make each thread use a separate random number generator (with a different but deterministic seed).
Sorry but I'm having a major brain fart here (guess that's what a few days of little sleep get you). Without changing anything to static how can I make a main() that will run this.
package merger;
import java.util.Random;
public class another {
public int[] numbers;
private final static int size = 100;
private static int maxNumber = 30;
private final static int limit = 10;
public int number;
private boolean Insertion = false;
public void arraytosort(){
numbers = new int[size];
Random number = new Random();
for (int i=0; i< numbers.length; i++){
numbers[i] = number.nextInt(maxNumber);
}
test(numbers);
}
public void test(int[] array){
this.numbers = array;
number = array.length;
mergesort(0,number - 1);
}
public void mergesort(int low, int high){
if(Insertion || high-low < limit){
insertionsort(low, high);
return;
}
if (low<high){
int middle = (low+high) / 2;
mergesort(low, middle);
mergesort(middle +1, high);
merge(low,middle,high);
return;
}
}
public void merge(int low, int middle, int high){
int[] temp = new int[number];
for (int i=low;i<=high; i++){
temp[i] = numbers[i];
}
int i = low;
int j = middle+1;
int k = low;
while (i<=middle || j<=high){
if (temp[i] <= temp[j]){
numbers[k] = temp[i];
i++;
}
else{
temp[k] = temp[j];
j++;
}
k++;
}
while (i<=middle){
temp[k] = temp[i];
k++;
i++;
}
temp = null;
return;
}
public void insertionsort(int low, int high){
for(int i=low+1;i<=high;i++){
int t = numbers[i];
for(int j = i-1; j>=low; j--){
if(t>numbers[j]) break;
numbers[j+1] = numbers[j];
numbers[j+1] = t;
}
}
}
/**
* #param args
*/
public static void main(String[] args){
}
}
I just need to be able to test it to see if this is working. In my head it seems like it should work.
Thanks
Without changing anything to static how can I make a main() that will run this.
You have to create an instance of the class:
public static void main(String[] args){
another instance = new another();
instance.whateverMethodYouLike();
}
BTW, please follow the Java convention and name classes with a capital first letter.
public static void main(String[] args)
{
another myObject = new another();
myObject.arraySort(); //will call test which will call mergesort
myObject.insertionSort(0,myObject.numbers.size()-1); //nothing calls insertion sort
}
PLEASE following code conventions like capitalizing first letter of class name and camelCasing for methods/variables.
If you want to see the sorted output, print the array on screen.
public variables is bad, bad, bad make them private (like numbers[]) in your case...
In the main method you "create" the instance of the object of that class and not directly call methods. It's a 'special' method so to speak different from other public/private/static methods...
I suggest reading up on some elementary java book like thinking in java which is available for free online...