Synchronized hashmap read-only access in Java - java

In Java, there are 3 threads that want to access (read-only) an immutable hashmap to do something. Is SynchronizedMap class below the fastest solution for that purpose? If not, then what would be faster to use?
import com.carrotsearch.hppc.IntObjectMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap;
public class abc {
public static void main(String[] args) {
final IntObjectMap<int[]> map = new IntObjectOpenHashMap<int[]>();
for (int i = 0; i < 4; i++) {
map.put(i, new int[] {1, 2, 3, 4, 5});
}
Thread[] threads = new Thread[3];
class SynchronizedMap {
private final Object syncObject = new Object();
public final int[] read(int i) {
final int[] value;
synchronized (syncObject) {
// code that reads-only immutable map object
value = map.get(i);
}
return value;
}
}
final SynchronizedMap syncMap = new SynchronizedMap();
class AccessMap implements Runnable {
private int id;
AccessMap(int index) { id = index; }
public void run() {
// code that reads-only immutable map object like this:
for (int i = 0; i < 4; i++) {
final int[] array = syncMap.read(i);
for (int j = 0; j < array.length; j++)
System.out.println(id + ": " + array[j] + " ");
}
}
}
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new AccessMap(i) {});
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Is SynchronizedMap class below the fastest solution for that purpose?
No. If the HashMap is truly immutable/read-only then a volatile Map<...> is the way to go.
volatile IntObjectMap<int[]> readOnlyMap = new IntObjectOpenHashMap<int[]>();
If you are starting your threads after your map is built then you don't even need the volatile. The only time you would need the volatile is if you are swapping in a new map that is being accessed by currently running threads.
final IntObjectMap<int[]> readOnlyMap = new IntObjectOpenHashMap<int[]>();

Related

Sum of all the elements in an array with ExecutorService pool not working

I am trying to understand ExecutorService and i want to do the sum of all the elements of an array. I did two methods, one that makes the sum serially (just a for loop that sums all the elements) and other concurrently with a pool. My problem is that the total sum from using ExecutorService is off with the serial sum almost all the time, sometimes even just by one.
package sumArregloConc;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class SumaArregloMain {
private final static int cantElem = 1000;
private static ExecutorService tpool = Executors.newCachedThreadPool();
public static void main(String[] args)
{
int[] arreglo = generarArreglo(cantElem); //generate the array with random numbers
System.out.println(sumaSerial(arreglo));
System.out.println(sumaConcurrente(arreglo));
}
public static int sumaSerial(int[] arreglo)
{
int suma = 0;
for(int i =0; i< arreglo.length; i++)
{
suma += arreglo[i];
}
return suma;
}
public static int sumaConcurrente(int[] arreglo)
{
AtomicInteger total = new AtomicInteger(0);
for(int i = 1 ; i < cantElem; i++){
int a = arreglo[i];
Thread thread = new Thread(new Runnable(){
public void run() {
int res = a;
total.addAndGet(res);
return;
}});
tpool.submit(thread);
}
tpool.shutdown(); //wait for everything to finish
return total.get();
}
public static int[] generarArreglo(int cantElem)
{
int[] arreglo = new int[cantElem];
Random rand = new Random();
for(int i = 0; i < cantElem; i++)
{
arreglo[i] = rand.nextInt(10);
}
return arreglo;
}
}
Can someone tell what is wrong?
Found the error. First what Eric said about awaitTermination and Runnable, but the main bug was just that the loop started at i = 1 instead of i = 0, silly mistake.
public static int sumaConcurrente(int[] arreglo)
{
AtomicInteger total = new AtomicInteger(0);
for(int i = 0 ; i < cantElem; i++){
int a = arreglo[i];
tpool.submit(new Runnable(){
public void run() {
total.addAndGet(a);
return;
}
});
}
tpool.shutdown(); //wait for everything to finish
try {
tpool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
}
return total.get();
}

Why is value set correctly even though we use different locks in different threads

Why is value set correctly even though we use different locks in different threads?
public class MyThread implements Runnable {
static String a = "LOCK";
static String b = "LOCK";
int id;
static int value = 0;
MyThread(int id) {
this.id = id;
}
#Override
public void run() {
if (id == 0) {
synchronized (a) {
for (int i = 0; i < Main.N; i++)
value = value + 3;
}
} else {
synchronized (b) {
for (int i = 0; i < Main.N; i++)
value = value + 3;
}
}
}
}
public class Main {
static final int N = 100000;
static int ITER = 100;
public static void main(String[] args) {
Thread threads[] = new Thread[2];
boolean sw = true;
for (int j = 0; j < ITER; j++) {
MyThread.value = 0;
for (int i = 0; i < 2; i++)
threads[i] = new Thread(new MyThread(i));
for (int i = 0; i < 2; i++)
threads[i].start();
for (int i = 0; i < 2; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (MyThread.value != 2 * 3 * N) {
System.out.println("i was different than " + 2 * 3 * N + ", it is " + MyThread.value);
sw = false;
}
}
if (sw)
System.out.println("Something is strange");
}
}
Java string literals are interned to save memory.
Your two "LOCK" strings (and therefore the two objects you lock on) are actually the same object.
This is (one of the reasons) why you should never lock on primitives.
Never use String as locks as there may well be the same instance of an other String because of the string pool.
In your case, your two "LOCK" strings are actually the same object.

Division of a task to threads - multi threading

I want to generate pairs from a given large pool of numbers. I am using two for loops and threads. My function getAllPairs() in the code generates apairs with a given array of numbers.
I have an array of length 1000. With one thread, output time is nearly 15 sec. Now I want to use 5-6 threads and reduce this output time.I am stuck at dividing this task equally to five threads.If not threads,how to decrease the output time?
Solution with threads is appreciated since I put a lot of time learning multithreading. I would like to implement it.
import java.util.*;
class Pair {
public int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString(){
return " ( " + x + " ," + y + " ) " ;
}
}
class selectPairs{
private int[] array;
private List<Pair> totalPairs ;
public selectPairs(int[] arr){
array = arr;
}
//set Method
public void settotalPairs(List<Pair> pieces){
totalPairs = pieces;
}
//get Method
public List<Pair> gettotalPairs(){
return totalPairs;
}
// Method to generate pairs
public List<Pair> getAllPairs() {
List<Pair> pairs = new ArrayList<Pair>();
int total = array.length;
for(int i=0; i < total; i++) {
int num1 = array[i];
for(int j=i+1; j < total; j++) {
int num2 = array[j];
pairs.add(new Pair(num1,num2));
}
}
return pairs;
}
}
// Thread class
class ThreadPairs extends Thread {
private Thread t;
selectPairs SP;
ThreadPairs(selectPairs sp){
SP = sp;
}
public void run() {
synchronized(SP) {
List<Pair> PAIRS = SP.getAllPairs();
SP.settotalPairs(PAIRS);
}
}
}
public class TestThread {
public static void main(String args[]) {
int[] a = new int[1000];
for (int i = 0; i < a.length; i++) {
a[i] = i ;
}
selectPairs ob = new selectPairs(a);
ThreadPairs T = new ThreadPairs( ob );
T.start();
while (true) {
try {
T.join();
break;
}
catch(Exception e){
}
}
List<Pair> Total = new ArrayList<Pair>() ;
List<Pair> Temp1 = ob.gettotalPairs();
Total.addAll(Temp1);
System.out.println(Total);
}
}
A solution with a thread-pool, a task split strategy and it collects all results:
public class SelectPairs {
private static final int NUM_THREADS = 8;
private int[] array;
public SelectPairs(int[] arr) {
array = arr;
}
// A splitting task strategy
public List<Pair> getPartialPairs(int threadIndex, int numThreads) {
List<Pair> pairs = new ArrayList<Pair>();
int total = array.length;
for (int i = threadIndex; i < total; i += numThreads) {
int num1 = array[i];
for (int j = i + 1; j < total; j++) {
int num2 = array[j];
pairs.add(new Pair(num1, num2));
}
}
return pairs;
}
// To use Callables or Runnables are better than extends a Thread.
public static class PartialPairsCall implements Callable<List<Pair>> {
private int thread;
private int totalThreads;
private SelectPairs selectPairs;
public PartialPairsCall(int thread, int totalThreads, SelectPairs selectPairs) {
this.thread = thread;
this.totalThreads = totalThreads;
this.selectPairs = selectPairs;
}
#Override
public List<Pair> call() throws Exception {
return selectPairs.getPartialPairs(thread, totalThreads);
}
}
public static void main(String[] args) throws Exception {
int[] a = new int[1000];
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
SelectPairs sp = new SelectPairs(a);
// Create a thread pool
ExecutorService es = Executors.newFixedThreadPool(NUM_THREADS);
List<Future<List<Pair>>> futures = new ArrayList<>(NUM_THREADS);
// Submit task to every thread:
for (int i = 0; i < NUM_THREADS; i++) {
futures.add(es.submit(new PartialPairsCall(i, NUM_THREADS, sp)));
}
// Collect the results:
List<Pair> result = new ArrayList<>(a.length * (a.length - 1));
for (Future<List<Pair>> future : futures) {
result.addAll(future.get());
}
// Shutdown thread pool
es.shutdown();
System.out.println("result: " + result.size());
}
}
regarding the framework of multithreading, you can implement ThreadPoolExecutor as was suggested in a comment.
Regarding splitting the workload, it seems that the key is splitting the iteration on the array which is achievable if you give the Runnable task a start and end index to iterate over.

java map concurrent update

I'm trying to create a Map with int values and increase them by multiple threads. two or more threads might increase the same key.
ConcurrentHashMap documentation was very unclear to me since it sais that:
Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove)
I wonder if the following code using ConcurrentHashMap will works correctly:
myMap.put(X, myMap.get(X) + 1);
if not, how can I manage such thing?
Concurrent map will not help thread safety of your code. You still can get race condition:
Thread-1: x = 1, get(x)
Thread-2: x = 1, get(x)
Thread-1: put(x + 1) => 2
Thread-2: put(x + 1) => 2
Two increments happened, but you still get only +1. You need a concurrent map only if you aim for modifying the map itself, not its content. Even the simplest HashMap is threadsafe for concurrent reads, given the map is not mutated anymore.
So instead of a threadsafe map for primitive type, you need a threadsafe wrapper for the type. Either something from java.util.concurrent.atomic or roll your own locked container if needing an arbitrary type.
One idea would be combining ConcurrentMap with AtomicInteger, which has a increment method.
AtomicInteger current = map.putIfAbsent(key, new AtomicInteger(1));
int newValue = current == null ? 1 :current.incrementAndGet();
or (more efficiently, thanks #Keppil) with an extra code guard to avoid unnecessary object creation:
AtomicInteger current = map.get(key);
if (current == null){
current = map.putIfAbsent(key, new AtomicInteger(1));
}
int newValue = current == null ? 1 : current.incrementAndGet();
Best practice. You can use HashMap and AtomicInteger.
Test code:
public class HashMapAtomicIntegerTest {
public static final int KEY = 10;
public static void main(String[] args) {
HashMap<Integer, AtomicInteger> concurrentHashMap = new HashMap<Integer, AtomicInteger>();
concurrentHashMap.put(HashMapAtomicIntegerTest.KEY, new AtomicInteger());
List<HashMapAtomicCountThread> threadList = new ArrayList<HashMapAtomicCountThread>();
for (int i = 0; i < 500; i++) {
HashMapAtomicCountThread testThread = new HashMapAtomicCountThread(
concurrentHashMap);
testThread.start();
threadList.add(testThread);
}
int index = 0;
while (true) {
for (int i = index; i < 500; i++) {
HashMapAtomicCountThread testThread = threadList.get(i);
if (testThread.isAlive()) {
break;
} else {
index++;
}
}
if (index == 500) {
break;
}
}
System.out.println("The result value should be " + 5000000
+ ",actually is"
+ concurrentHashMap.get(HashMapAtomicIntegerTest.KEY));
}
}
class HashMapAtomicCountThread extends Thread {
HashMap<Integer, AtomicInteger> concurrentHashMap = null;
public HashMapAtomicCountThread(
HashMap<Integer, AtomicInteger> concurrentHashMap) {
this.concurrentHashMap = concurrentHashMap;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
concurrentHashMap.get(HashMapAtomicIntegerTest.KEY)
.getAndIncrement();
}
}
}
Results:
The result value should be 5000000,actually is5000000
Or HashMap and synchronized, but much slower than the former
public class HashMapSynchronizeTest {
public static final int KEY = 10;
public static void main(String[] args) {
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
hashMap.put(KEY, 0);
List<HashMapSynchronizeThread> threadList = new ArrayList<HashMapSynchronizeThread>();
for (int i = 0; i < 500; i++) {
HashMapSynchronizeThread testThread = new HashMapSynchronizeThread(
hashMap);
testThread.start();
threadList.add(testThread);
}
int index = 0;
while (true) {
for (int i = index; i < 500; i++) {
HashMapSynchronizeThread testThread = threadList.get(i);
if (testThread.isAlive()) {
break;
} else {
index++;
}
}
if (index == 500) {
break;
}
}
System.out.println("The result value should be " + 5000000
+ ",actually is" + hashMap.get(KEY));
}
}
class HashMapSynchronizeThread extends Thread {
HashMap<Integer, Integer> hashMap = null;
public HashMapSynchronizeThread(
HashMap<Integer, Integer> hashMap) {
this.hashMap = hashMap;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
synchronized (hashMap) {
hashMap.put(HashMapSynchronizeTest.KEY,
hashMap
.get(HashMapSynchronizeTest.KEY) + 1);
}
}
}
}
Results:
The result value should be 5000000,actually is5000000
Use ConcurrentHashMap will get the wrong results.
public class ConcurrentHashMapTest {
public static final int KEY = 10;
public static void main(String[] args) {
ConcurrentHashMap<Integer, Integer> concurrentHashMap = new ConcurrentHashMap<Integer, Integer>();
concurrentHashMap.put(KEY, 0);
List<CountThread> threadList = new ArrayList<CountThread>();
for (int i = 0; i < 500; i++) {
CountThread testThread = new CountThread(concurrentHashMap);
testThread.start();
threadList.add(testThread);
}
int index = 0;
while (true) {
for (int i = index; i < 500; i++) {
CountThread testThread = threadList.get(i);
if (testThread.isAlive()) {
break;
} else {
index++;
}
}
if (index == 500) {
break;
}
}
System.out.println("The result value should be " + 5000000
+ ",actually is" + concurrentHashMap.get(KEY));
}
}
class CountThread extends Thread {
ConcurrentHashMap<Integer, Integer> concurrentHashMap = null;
public CountThread(ConcurrentHashMap<Integer, Integer> concurrentHashMap) {
this.concurrentHashMap = concurrentHashMap;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
concurrentHashMap.put(ConcurrentHashMapTest.KEY,
concurrentHashMap.get(ConcurrentHashMapTest.KEY) + 1);
}
}
}
Results:
The result value should be 5000000,actually is11759
You could just put the operation in a synchronized (myMap) {...} block.
Your current code changes the values of your map concurrently so this will not work.
If multiple threads can put values into your map, you have to use a concurrent map like ConcurrentHashMap with non thread safe values like Integer. ConcurrentMap.replace will then do what you want (or use AtomicInteger to ease your code).
If your threads will only change the values (and not add/change the keys) of your map, then you can use a standard map storing thread safe values like AtomicInteger. Then your thread will call:map.get(key).incrementAndGet() for instance.

Java MultiThreading Code Error

I am trying to learn multithreading concepts in Java. I am stuck with error during execution of my code snippet.
My code snippet:
class ThreadDemo {
public static void main(String args[]) {
try{
int [] arr = new int[10] ;
for(int i = 0 ; i < 10 ; i++)
arr[i] = i ;
for(int c =0 ; c < 2 ; c++){
for(int i = 0 ; i < 3 ; i++) //I want to run it on one thread
System.out.println(arr[i]);
for(int j = 0 ; j < 5 ; j++) //I want to run it on another thread
System.out.println(arr[j]);
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
Now, to solve this I have tried,
class ThreadDemo {
public static void main(String args[]) {
try{
int [] arr = new int[10] ;
for(int i = 0 ; i < 10 ; i++)
arr[i] = i ;
for(int c =0 ; c < 2 ; c++){
Thread thread1 = new Thread () {
public void run () {
for(int i = 0 ; i < 3 ; i++) //I want to run it on one thread
System.out.println(arr[i]);}
};
Thread thread2 = new Thread () {
public void run () {
for(int j = 0 ; j < 5 ; j++) //I want to run it on one thread
System.out.println(arr[j]);}
};
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
But gives error. Can anyone help me how to solve this ?
In
for (int c = 0; c < 2; c++) {
Thread thread1 = new Thread() {//<- here
you are creating anonymous inner class that extends Thread class. You must know, that anonymous inner classes have access only to final local variables of method that they are created so if you want to gain access to int [] arr you must make it final like
final int[] arr = new int[10];
Also you created threads but you didn't start them. To do that invoke their start() method like thread1.start().
If you don't want to declare local variables of method as final you should consider creating threads not as anonymous inner classes but as separate classes for example
class MyThread extends Thread {
int[] array;
int iterations;
public MyThread(int[] arr, int i) {
array=arr;
iterations = i;
}
#Override
public void run() {
for (int i = 0; i < iterations; i++)
System.out.println(array[i]);
}
}
class ThreadDemo {
public static void main(String args[]) {
try {
int[] arr = new int[10];
for (int i = 0; i < 10; i++)
arr[i] = i;
for (int c = 0; c < 2; c++) {
MyThread thread1 = new MyThread(arr, 3);
MyThread thread2 = new MyThread(arr, 5);
thread1.start();
thread2.start();
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
FYI: Extending Thread is not the best idea if you're not actually providing any additional logic to it. It's best to use a Runnable and pass it to the threads constructor.
Thread t = new Thread(new Runnable() {
public void run() {
}
});
t.start();
Aside from that, as someone else noted, any variables directly in an anonymous class need to be declared as final.

Categories

Resources