Java Integer Accumulator optimisation - java

I need to write Integer Accumulator. Implementation needs to be thread-safe and efficient under high thread contention.
Usage example:
Accumulator accumulator = new AccumulatorSum();
int firstSum = accumulator.accumulate(1, 2, 3);
int secondSum = accumulator.accumulate(4);
int total = accumulator.getTotal();
In this case, the value of firstSum is 6, secondSum is 4 and the value of total is 10.
Calling accumulator.reset() would reset the total value to 0.
Code below is something that I've managed to do. Do you think it is thread-safe, guarantees consistency and efficient enough?
Thanks for any help!
public class AccumulatorSum implements Accumulator{
private ReadWriteLock rwlock = new ReentrantReadWriteLock();
private Integer totalSum = 0;
#Override
public int accumulate(int... values) {
int sum = 0;
for(int v : values){
sum += v;
}
rwlock.writeLock().lock();
try {
totalSum += sum;
}
finally {
rwlock.writeLock().unlock();
}
return sum;
}
#Override
public int getTotal() {
rwlock.readLock().lock();
try {
return totalSum;
}
finally {
rwlock.readLock().unlock();
}
}
#Override
public void reset() {
rwlock.writeLock().lock();
try{
totalSum = 0;
}
finally {
rwlock.writeLock().unlock();
}
}

Related

Java Threads (Beginner)

I'm having an issue dealing with my java code here.
I was sure I've used al recommandation I've founded online. But it still doesn't work.
import java.util.*;
import java.util.concurrent.*;
import java.util.Map;
public class GradeCounterImpl implements GradeCounter {
ConcurrentHashMap<String, GradeCount> save;
public GradeCount[] count(String[] grades, int nThreads) {
if (grades == null) {
return new GradeCount[0];
}
if (grades.length == 0) {
return new GradeCount[0];
}
save = new ConcurrentHashMap<>();
class WorkUnit implements Runnable {
final String[] positions;
public WorkUnit(String[] i) {
this.positions = i;
}
public void run() {
for (String pos : positions)
if (pos != null) {
if (save.containsKey(pos)) {
save.get(pos).count++;
} else {
save.put(pos, new GradeCount(pos, 1));
}
}
}
}
int divide = (grades.length / nThreads);
ExecutorService exe = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < nThreads; i++)
exe.execute(new WorkUnit(arrayBetween(i * divide, (i + 1) * divide, grades)));
exe.shutdown();
try {
exe.awaitTermination(30, TimeUnit.MINUTES);
} catch (InterruptedException error) {
error.printStackTrace();
}
Collection<GradeCount> c = save.values();
return c.toArray(new GradeCount[c.size()]);
}
private String[] arrayBetween(int start, int end, String[] target) {
String[] ans = new String[end - start];
for (int i = start; i < end; i++)
if (i < target.length)
ans[i - start] = target[i];
return ans;
}
}
public class GradeCount implements Comparable<GradeCount> {
public String grade;
public int count;
public GradeCount(final String grade, final int count) {
this.grade = grade;
this.count = count;
}
public int compareTo(final GradeCount other) {
final int gradeCmp = this.grade.compareTo(other.grade);
return gradeCmp == 0 ? Integer.compare(this.count, other.count) : gradeCmp;
}
}
What it's to do ?
The code must be counting every String appearing in the grades array and saving the results in the hashmap and then returning their values.
What's the problem ?
The code isn't (as you can guest with the title) not working fine. It doesn't count well and I'm having huge difference between big arrays tests.
Observations :
When I test with small arrays (0 - 50 values), the program run well
Now : What should I do ?
Thanks you for reading all here and I hope you can help me.
The problem is here:
if (save.containsKey(pos)) {
save.get(pos).count++;
} else {
save.put(pos, new GradeCount(pos, 1));
}
You have a ConcurrentHashMap but your GradeCounter is not synchornized, hence call to count++ will not correct
I think your GradeCount look like {grade, count} so I suggest you to use Map<String, AtomicInteger> isntead

Turning a program using multi-threading into a program that uses blocking queues

I am currently trying to turn a program that is currently using multi-threading, locks etc. into a program that using blocking queues instead. The point is to remove all the multi-threading code. There will be 100 producer threads. The producer threads are all busy producing transaction objects (each one different) and putting them to the queue. The one consumer thread will continuously remove transactions from the queue and process them. In other words, loop forever. However, the looping forever part in the consumer thread is not working out. I want to only use one consumer thread. And with my code I am only getting one line of output when the lines of output should go on forever until the program is stopped. Here is my code any help will be appreciated and thanks in advance.
import java.util.*;
import java.util.concurrent.*;
public class SynchBankTest
{
public static final int NACCOUNTS = 100;
public static final double INITIAL_BALANCE = 1000;
public static final int DELAY = 10;
public static final Transaction tr = new Transaction();
public static void main(String[] args)
{
BlockingQueue<Transaction> queue = new ArrayBlockingQueue<>(30);
Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
for (int i = 0; i < NACCOUNTS; i++)
{
Runnable p = () -> {
try
{
while (true)
{
queue.put(tr);
Thread.sleep((int) (DELAY * Math.random()));
}
}
catch (InterruptedException e)
{
}
};
Thread pt = new Thread(p);
pt.start();
}
Runnable c = () -> {
double amount = 0;
int fromAcct = 0;
int toAcct = 0;
amount = tr.getAmount();
fromAcct = tr.getFromAccount();
toAcct = tr.getToAccount();
bank.transfer(fromAcct, toAcct, amount);
};
Thread ct = new Thread(c);
ct.start();
}
}
class Transaction
{
private double amount;
private int toAccount;
private int fromAccount;
private static final double MAX_AMOUNT = 1000;
private Bank bank = new Bank(100, 1000);
public Transaction()
{
}
public int getToAccount()
{
toAccount = (int) (bank.size() * Math.random());
return toAccount;
}
public int getFromAccount()
{
for (int i = 0; i < 100; i++)
{
fromAccount = i;
}
return fromAccount;
}
public double getAmount()
{
amount = MAX_AMOUNT * Math.random();
return amount;
}
}
class Bank
{
private final double[] accounts;
public Bank(int n, double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
}
public void transfer(int from, int to, double amount)
{
if (accounts[from] < amount) return;
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
}
public double getTotalBalance()
{
try
{
double sum = 0;
for (double a : accounts)
sum += a;
return sum;
}
finally
{
}
}
public int size()
{
return accounts.length;
}
}
Like said above, the consumer thread needs to have an infinite loop, which I did not have. This solved my issue:
Runnable c = () -> {
try{
while(true)
{
tr = queue.take();
double amount = 0;
int fromAcct = 0;
int toAcct = 0;
amount = tr.getAmount();
fromAcct = tr.getFromAccount();
toAcct = tr.getToAccount();
bank.transfer(fromAcct, toAcct, amount);
}
}
catch(InterruptedException e)
{
}
};
Thread ct = new Thread(c);
ct.start();

ArrayIndexOutOfBoundsException at method of concurrency approaches comprise

I want to run some comparison of different approaches for concurrency technique.
But it throws next exceptions:
Warmup
BaseLine : 21246915
============================
Cycles : 50000
Exception in thread "pool-1-thread-3" Exception in thread "pool-1-thread-5" java.lang.ArrayIndexOutOfBoundsException: 100000
at concurrency.BaseLine.accumulate(SynchronizationComparisons.java:89)
at concurrency.Accumulator$Modifier.run(SynchronizationComparisons.java:39)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
java.lang.ArrayIndexOutOfBoundsException: 100000
at concurrency.BaseLine.accumulate(SynchronizationComparisons.java:89)
at concurrency.Accumulator$Modifier.run(SynchronizationComparisons.java:39)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
Here is code:
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.*;
import static net.mindview.util.Print.*;
abstract class Accumulator {
public static long cycles = 50000L;
// Number of Modifiers and Readers during each test:
private static final int N = 4;
public static ExecutorService exec = Executors.newFixedThreadPool(N * 2);
private static CyclicBarrier barrier = new CyclicBarrier(N * 2 + 1);
protected volatile int index = 0;
protected volatile long value = 0;
protected long duration = 0;
protected String id = "error";
protected final static int SIZE = 100000;
protected static int[] preLoaded = new int[SIZE];
static {
// Load the array of random numbers:
Random rand = new Random(47);
for (int i = 0; i < SIZE; i++)
preLoaded[i] = rand.nextInt();
}
public abstract void accumulate();
public abstract long read();
private class Modifier implements Runnable {
public void run() {
for (long i = 0; i < cycles; i++)
accumulate();
try {
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private class Reader implements Runnable {
#SuppressWarnings("unused")
private volatile long value;
public void run() {
for (long i = 0; i < cycles; i++)
value = read();
try {
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public void timedTest() {
long start = System.nanoTime();
for (int i = 0; i < N; i++) {
exec.execute(new Modifier());
exec.execute(new Reader());
}
try {
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
duration = System.nanoTime() - start;
printf("%-13s: %13d\n", id, duration);
}
public static void report(Accumulator acc1, Accumulator acc2) {
printf("%-22s: %.2f\n", acc1.id + "/" + acc2.id, (double) acc1.duration / (double) acc2.duration);
}
}
class BaseLine extends Accumulator {
{
id = "BaseLine";
}
public void accumulate() {
value += preLoaded[index++];
if (index >= SIZE)
index = 0;
}
public long read() {
return value;
}
}
class SynchronizedTest extends Accumulator {
{
id = "synchronized";
}
public synchronized void accumulate() {
value += preLoaded[index++];
if (index >= SIZE)
index = 0;
}
public synchronized long read() {
return value;
}
}
class LockTest extends Accumulator {
{
id = "Lock";
}
private Lock lock = new ReentrantLock();
public void accumulate() {
lock.lock();
try {
value += preLoaded[index++];
if (index >= SIZE)
index = 0;
} finally {
lock.unlock();
}
}
public long read() {
lock.lock();
try {
return value;
} finally {
lock.unlock();
}
}
}
class AtomicTest extends Accumulator {
{
id = "Atomic";
}
private AtomicInteger index = new AtomicInteger(0);
private AtomicLong value = new AtomicLong(0);
public void accumulate() {
// Oops! Relying on more than one Atomic at
// a time doesn't work. But it still gives us
// a performance indicator:
int i = index.getAndIncrement();
value.getAndAdd(preLoaded[i]);
if (++i >= SIZE)
index.set(0);
}
public long read() {
return value.get();
}
}
public class SynchronizationComparisons {
static BaseLine baseLine = new BaseLine();
static SynchronizedTest synch = new SynchronizedTest();
static LockTest lock = new LockTest();
static AtomicTest atomic = new AtomicTest();
static void test() {
print("============================");
printf("%-12s : %13d\n", "Cycles", Accumulator.cycles);
baseLine.timedTest();
synch.timedTest();
lock.timedTest();
atomic.timedTest();
Accumulator.report(synch, baseLine);
Accumulator.report(lock, baseLine);
Accumulator.report(atomic, baseLine);
Accumulator.report(synch, lock);
Accumulator.report(synch, atomic);
Accumulator.report(lock, atomic);
}
public static void main(String[] args) {
int iterations = 5; // Default
if (args.length > 0) // Optionally change iterations
iterations = new Integer(args[0]);
// The first time fills the thread pool:
print("Warmup");
baseLine.timedTest();
// Now the initial test doesn't include the cost
// of starting the threads for the first time.
// Produce multiple data points:
for (int i = 0; i < iterations; i++) {
test();
Accumulator.cycles *= 2;
}
Accumulator.exec.shutdown();
}
}
How to solve this trouble?
The array preLoaded is of size 100000. So, the valid index starts from 0 to 99999 since array index starts from 0. You need to swap the statements in method accumulate()
Change this
value += preLoaded[index++]; //index validity is not done
if (index >= SIZE)
index = 0;
to
if (index >= SIZE)
index = 0;
value += preLoaded[index++]; // index validity is done and controlled
This will not make the index go to 100000. It will make it to 0 when it turns 100000 before the index value is accessed.
Note : The above code is vulnerable only in multi-threaded environment. The above code will work fine with single thread.
Change BaseLine class and AtomicTest class:
class BaseLine extends Accumulator {
{
id = "BaseLine";
}
public void accumulate() {
int early = index++; // early add and assign to a temp.
if(early >= SIZE) {
index = 0;
early = 0;
}
value += preLoaded[early];
}
public long read() {
return value;
}
}
class AtomicTest extends Accumulator {
{
id = "Atomic";
}
private AtomicInteger index = new AtomicInteger(0);
private AtomicLong value = new AtomicLong(0);
public void accumulate() {
int early = index.getAndIncrement();
if(early >= SIZE) {
index.set(0);
early = 0;
}
value.getAndAdd(preLoaded[early]);
}
public long read() {
return value.get();
}
}
I suspect that you're running into concurrent executions of BaseLine.accumulate() near the boundary of the preLoaded array.
You've got 4 threads hammering away at an unsynchronized method, which is potentially leading to index being incremented to 100000 by say, Thread 1, and before Thread 1 can set it back to 0, one of Thread 2, 3 or 4 is coming in and attempting to access preLoaded[index++], which fails as index is still 100000.

Java ExecutorService Performance

Hi I have implemented a method that calculated the Mode value from an array of millions of elements (integers).
I am now comparing a sequential version to a (supposed to be ) improved version that makes use of the Executor Service... unfortunately the performance is not as good as expected:
Sequentiallly iterating hashMap (version 0)
#size #time #memory
10000000 13772ms 565mb
20000000 35355ms 1135mb
30000000 45879ms 1633mb
Assigning jobs to a Service Executor (version 2)
#size #time #memory
10000000 16186ms 573mb
20000000 34561ms 1147mb
30000000 54792ms 1719mb
The code for the Executor Service is as follows:
/* Optimised-Threaded Method to calculate the Mode */
private int getModeOptimisedThread(int[] mybigarray){
System.out.println("calculating mode (optimised w/ ExecutorService)... ");
int mode = -1;
//create an hashmap to calculating the frequencies
TreeMap<Integer, Integer> treemap = new TreeMap<Integer, Integer>();
//for each integer in the array, we put an entry into the hashmap with the 'array value' as a 'key' and frecuency as 'value'.
for (int i : mybigarray) {
//we check if that element already exists in the Hashmap, by getting the element with Key 'i'
// if the element exists, we increment the frequency, otherwise we insert it with frecuency = 1;
Integer frequency = treemap.get(i);
int value = 0;
if (frequency == null){ //element not found
value = 1;
}
else{ //element found
value = frequency + 1;
}
//insert the element into the hashmap
treemap.put(i, value);
}
//Look for the most frequent element in the Hashmap
int maxCount = 0;
int n_threads = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(n_threads);
//create a common variable to store maxCount and mode values
Result r = new Result(mode, maxCount);
//set the umber of jobs
int num_jobs = 10;
int job_size = treemap.size()/num_jobs;
System.out.println("Map size "+treemap.size());
System.out.println("Job size "+job_size);
//new MapWorker(map, 0, halfmapsize, r);
int start_index, finish_index;
List<Callable<Object>> todolist = new ArrayList<Callable<Object>>(num_jobs);
//assign threads to pool
for (int i=0; i<num_jobs; i++)
{
start_index=i*job_size;
finish_index = start_index+job_size;
System.out.println("start index: "+start_index+". Finish index: "+finish_index);
todolist.add(Executors.callable(new MapWorker(treemap.subMap(start_index, finish_index), r)));
}
try{
//invoke all will not return until all the tasks are completed
es.invokeAll(todolist);
} catch (Exception e) {
System.out.println("Error in the Service executor "+e);
} finally {
//finally the result
mode = r.getMode();
}
//return the result
return mode;
}
Any suggestion about the quality of the Executor Service's code?
Please suggest, it's the first time I implement the E.S.
Edit:
Worker
public class MapWorker implements Runnable{
private int index;
private int size;
private int maxCount;
private Result result;
private Map <Integer, Integer> map;
//Constructor
MapWorker( Map <Integer, Integer> _map, Result _result){
this.maxCount = 0;
this.result = _result;
map = _map;
}
public void run(){
for (Map.Entry<Integer, Integer> element : map.entrySet()) {
if (element.getValue() > result.getCount()) {
result.setNewMode(element.getKey(),element.getValue());
}
}
}
}
and Result class:
public class Result {
private int mode;
private int maxCount;
Result(int _mode, int _maxcount){
mode = _mode;
maxCount = _maxcount;
}
public synchronized void setNewMode(int _newmode, int _maxcount) {
this.mode = _newmode;
this.maxCount = _maxcount;
}
public int getMode() {
return mode;
}
public synchronized int getCount() {
return maxCount;
}
}
for each job, use separate Result object (without synchronization). When all jobs finish, chose result with maximum value.
int num_jobs = n_threads;
The chunk of the work is being done while computing the frequencies. That will significantly dominate any benefits of parallelism you will get by trying to update the results. You need to work on parallelizing the computation of the mode by each worker computing frequencies locally before updating a global frequency at the end. You can consider using AtomicInteger to store the mode in the global store to ensure thread safety. Once the frequencies have been computed, you can compute the mode sequentially at the end as it will have much lower computation cost to traverse the map sequentially.
Something like the following should work better:
EDIT: modified the updateScore() method to fix a data race.
private static class ResultStore {
private Map<Integer, AtomicInteger> store = new ConcurrentHashMap<Integer, AtomicInteger>();
public int size() {
return store.size();
}
public int updateScore(int key, int freq) {
AtomicInteger value = store.get(key);
if (value == null) {
store.putIfAbsent(key, new AtomicInteger(0));
value = store.get(key);
}
return value.addAndGet(freq);
}
public int getMode() {
int mode = 0;
int modeFreq = 0;
for (Integer key : store.keySet()) {
int value = store.get(key).intValue();
if (modeFreq < value) {
modeFreq = value;
mode = key;
}
}
return mode;
}
}
private static int computeMode(final int[] mybigarray) {
int n_threads = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(n_threads);
final ResultStore rs = new ResultStore();
//set the number of jobs
int num_jobs = 10;
int job_size = mybigarray.length / num_jobs;
System.out.println("Map size " + mybigarray.length);
System.out.println("Job size " + job_size);
List<Callable<Object>> todolist = new ArrayList<Callable<Object>>(num_jobs);
for (int i = 0; i < num_jobs; i++) {
final int start_index = i * job_size;
final int finish_index = start_index + job_size;
System.out.println("Start index: " + start_index + ". Finish index: " + finish_index);
todolist.add(Executors.callable(new Runnable() {
#Override
public void run() {
final Map<Integer, Integer> localStore = new HashMap<Integer, Integer>();
for (int i = start_index; i < finish_index; i++) {
final Integer loopKey = mybigarray[i];
Integer loopValue = localStore.get(loopKey);
if (loopValue == null) {
localStore.put(loopKey, 1);
} else {
localStore.put(loopKey, loopValue + 1);
}
}
for (Integer loopKey : localStore.keySet()) {
final Integer loopValue = localStore.get(loopKey);
rs.updateScore(loopKey, loopValue);
}
}
}));
}
try {
//invoke all will not return until all the tasks are completed
es.invokeAll(todolist);
} catch (Exception e) {
System.out.println("Error in the Service executor " + e);
}
return rs.getMode();
}

Java - Error Message Help

In the Code, mem is a of Class Memory and getMDR and getMAR ruturn ints. When I try to compile the code I get the following errors.....how can I fix this?
Computer.java:25: write(int,int) in Memory cannot be applied to (int)
Input.getInt(mem.write(cpu.getMDR()));
^
Computer.java:28: write(int,int) in Memory cannot be applied to (int)
mem.write(cpu.getMAR());
Here is the code for Computer:
class Computer{
private Cpu cpu;
private Input in;
private OutPut out;
private Memory mem;
public Computer()
{
Memory mem = new Memory(100);
Input in = new Input();
OutPut out = new OutPut();
Cpu cpu = new Cpu();
System.out.println(in.getInt());
}
public void run()
{
cpu.reset();
cpu.setMDR(mem.read(cpu.getMAR()));
cpu.fetch2();
while (!cpu.stop())
{
cpu.decode();
if (cpu.OutFlag())
OutPut.display(mem.read(cpu.getMAR()));
if (cpu.InFlag())
Input.getInt(mem.write(cpu.getMDR()));
if (cpu.StoreFlag())
{
mem.write(cpu.getMAR());
cpu.getMDR();
}
else
{
cpu.setMDR(mem.read(cpu.getMAR()));
cpu.execute();
cpu.fetch();
cpu.setMDR(mem.read(cpu.getMAR()));
cpu.fetch2();
}
}
}
Here is the code for Memory:
class Memory{
private MemEl[] memArray;
private int size;
public Memory(int s)
{size = s;
memArray = new MemEl[s];
for(int i = 0; i < s; i++)
memArray[i] = new MemEl();
}
public void write (int loc, int val)
{if (loc >=0 && loc < size)
memArray[loc].write(val);
else
System.out.println("Index Not in Domain");
}
public int read (int loc)
{return memArray[loc].read();
}
public void dump()
{
for(int i = 0; i < size; i++)
if(i%1 == 0)
System.out.println(memArray[i].read());
else
System.out.print(memArray[i].read());
}
}
Here is the code for getMAR and getMDR:
public int getMAR()
{
return ir.getOpcode();
}
public int getMDR()
{
return mdr.read();
}
Your Memory class has a method write(int, int).
You call it with a single int. As if it was write(int).
Java complains about that: "Computer.java:28: write(int,int) in Memory cannot be applied to (int)". So either you are missing your location (loc) parameter or your value (val) parameter; depending on what code is supposed to be actually doing.

Categories