Multi threads in Java - java

I have some class. For example:
public class Data {
private String name;
public Data(String url) {
// There is download something from the Internet and set field "name".
}
public String getName() {
return name;
}
}
In some method I need to initialize array of objects Data.
ArrayList<Data> list = new ArrayList<Data>;
for(int i=0; i<max; i++) {
list.add(new Data("http://localhost/" + String.valueOf(i)));
}
But it is to long. I wanna do this:
final ArrayList<Data> list = new ArrayList<Data>;
for(int i=0; i<max; i++) {
final int tmp = i;
new Thread() {
public void run() {
list.add(new Data("http://localhost/" + String.valueOf(tmp)));
}
}.start();
}
But the main thread ends sooner than the others and variable list is empty. What should I do? Help pls :)
UP. That is not too fast to download some data from the Internet that's why I've created several threads.

Instead of dealing with the low level details of the Thread API, you could use the java concurrent package, with an executor to handle the threads (I don't know what ListArray is but if it is not thread safe you will have issues with the solution proposed some of the other answers: adding a join will not be sufficient).
For example, a simplified example would be:
final ExecutorService executor = Executors.newFixedThreadPool(10);
final List<Future<Data>> list = new ArrayList<Future<Data>>(max);
for (int i = 0; i < max; i++) {
final int tmp = i;
Callable<Data> c = new Callable<Data>() {
#Override
public Data call() {
return new Data("http://localhost/" + tmp);
}
};
list.add(executor.submit(c));
}
executor.shutdown();
for (Future<Data> future : list) {
Data data = future.get(); //will block until the page has been downloaded
//use the data
}
Ideally, you whould add some error handling around future.get(), as it will throw an ExecutionException if your task throws an exception, which I suppose could happen if the page is not availble for example.

1. When you fire the Another thread, that does the work of getting the data from net and populating the list, immediately after that use join() method.
2. join() method will not let the next line to execute before the run() method of the thread on which it is called has finish().
3. So your main() method will not be executed before the list is populated as you have used join() to hold the execution before the other thread is done.....

In your main use Thread.join to wait for the child threads to complete
Thread[] threads = new Thread[max];
final List<Data> list = Collections.synchronizedList(new ArrayList<Data>());
for(int i=0; i< max; i++) {
final int tmp = i;
Thread t = new Thread() {
public void run() {
list.add(new Data("http://localhost/" + String.valueOf(tmp)));
}
};
t.start();
threads[i] = t;
}
for (Thread t : threads) {
t.join();
}

Related

What is the proper way to let threads print out sequentially using join

I am curious about how to let the threads print out sequentially using join().(Any other ways are also welcome.) For example, I have the code as following:
private static class LittleThread implements Runnable {
int val;
public LittleThread(int i) {
val = i;
}
public void run() {
System.out.println("Thread " + val + " finished.");
}
}
public static void main(String[] args) throws Exception {
for (int i = 1; i <= 10; i++) {
new Thread(new LittleThread(i)).start();
}
}
I am wondering, how do we do with this code, to make the main() prints sequentially:
Thread 1 finished.
Thread 2 finished.
Thread 3 finished.
...
To make a number of Runnable objects, executed in a separate Thread, execute sequentially, you should use the single thread ExecutorService:
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
executor.submit(new LittleThread(i));
}
executor.shutdown();
}
The ExecutorService is responsible for proper management of the Thread objects (ok, all one of them in this case) ... creating them (it) as needed, and terminating them by calling join (as the service is shutdown).

some elements processed more than once, some not at all

I have a fairly straightforward task: I have a list of strings each of which is processed and a score is produced. The string and its score then get added to a map:
public class My1Thread
{
final private static List<String> ids = Arrays.asList("id1","id2","id3","id4","id5");
private static HashMap<String,Double> result = null;
private Double computeResult(String id)
{
Double res = 0.0;
// do stuff to compute result
return res;
}
public static void main(String[] args)
{
result = new HashMap<String,Double>();
for (String id: ids)
{
result.put(id,computeResult(id));
}
}
}
Since scores of any two strings are independent of each other, this seems to be a perfect case to use multithreading. However, I am getting unexpected results, which is probably a typical result for a multithreading newbie.
Here's a m/t version of the above:
public class MyMultiThread
{
final private static int nWorkers = 3; // number of threads
final private static List<String> ids = Arrays.asList("id1","id2","id3","id4","id5");
private static int curIndex = 0; // indexing pointing to position in ids currently being processed
private static HashMap<String,Double> result = null;
public static class Worker implements Runnable {
private int id;
public Worker(int id) {
this.id = id;
}
synchronized void setCounter(final int counter)
{
curIndex = counter;
}
synchronized int getCounter()
{
return curIndex;
}
synchronized void addToResult(final String id, final Double score)
{
result.put(id,score);
}
#Override
public void run()
{
try {
while (true)
{
int index = getCounter();
if (index >= ids.size())
{
// exit thread
return;
}
String id = ids.get(index);
setCounter(index+1);
System.out.print(String.format("Thread %d: processing %s from pos %d\n", id, id, curIndex-1));
Double score = ... // compute score here
addToResult(id,score);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args)
{
result = new HashMap<String,ArrayList<Pair<Document,Double>>>();
for (int i = 0; i < nWorkers; i++) {
Thread worker = new Thread(new MyMultiThread.Worker(i));
worker.start();
}
}
}
According to the output produced by System.out.print, this code appears to be processing some elements of ids more than once while not processing others at all. What am I doing wrong here?
Your while(true) loop inside the thread starts at the index specified in the constructor, and then increment it by one, and then the loop starts again. So thread 0 does index 0, then index 1, etc.. Thread 1 does index 1, then index 2, etc... So index 2 will be done 3 times.
I would use a synchronized linked list for ids, and have each thread take and remove the first element of the list, until the list is empty. Use LinkedList.removeFirst().
Also the result hash map also needs to be synchronized, since multiple threads may write to it at the same time.
The problem is that the map is being modified concurrently in multiple threads, so some updates are getting lost.
You declared the methods that modify the map as synchronized, but note that they are synchronized on multiple worker objects: not on a single object, which would provide the locking you are after.
I'd recommend using ConcurrentHashMap and getting rid of all the synchronized declarations.
Some of your synchronization is too narrow - for example, this bit here:
int index = getCounter();
if (index >= ids.size())
{
// exit thread
return;
}
String id = ids.get(index);
setCounter(index+1);
What happens if thread A reads the counter, thread B reads the counter, then thread A updates the counter?
A: int index = getCounter(); // returns 3
B: int index = getCounter(); // returns 3
...
A: setCounter(index + 1); // sets it to 4
B: setCounter(index + 1); // Uh-oh, sets it to 4 as well, we lost an update!
In this case, when you read a variable, then write to it based on the value you read, both the read and the write need to be within the same synchronization block. Declaring getCounter and setCounter as synchronized is not enough.
Simply use Java 8 Stream API :
Map<String, Double> map = ids.parallelStream().collect(Collectors.toConcurrentMap(id -> id, id -> computeScore(id)));
...
Double computeScore(String id) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ThreadLocalRandom.current().nextDouble(100);
}
Here's a nice tutorial.

Concurrency in java

public class MyTest {
ArrayList<Integer> array = new ArrayList<>();
public void initialize() {
//....
}
private void editArray(int num) {
// modified the array
}
public void func(int n) {
for (int i = 0; i < n; i++) {
editArray(i);
}
}
}
I hope to execute "editArray" function in the forloop concurrently, which means n threads(call editArray function) can execute concurrently, how can I do that and add a lock for ArrayList array ? I google a lot, most of tutorials just teach how to spawn thread for different objects. What I want is that spawn thread in a single object.
I mainly want to know how to call a function concurrently in java.
Thanks.

Return Value from Java Thread Class

So below is a simple Java class using multithreading, and my question is, is there a way for me to store the randomNumber from each thread (maybe in a variable called randomNumberOne or randomNumberTwo), so that I can use those to possibly get the sum of both and return it?
I know this example sounds stupid but basically with my real code I am returning a value from each of my threads and want to get the average of them. I haven't found any solution for returning values in threads in java (also I am new to multithreading completely).
public class Example {
public static void main(String[] args){
MathThread one = new MathThread();
MathThread two = new MathThread();
one.start();
two.start();
}
}
class MathThread extends Thread{
public MathThread(){
}
public void run(){
Random rand = new Random();
int randomNumber = rand.nextInt((100 - 1) + 1) + 1;
System.out.println(randomNumber);
}
Output
5
33
Add a result variable to your MathThread class and get the value after you join the thread:
class MathThread extends Thread
{
private int result;
public int getResult()
{
this.join();
return result;
}
public void run()
{
// ...
result = randomNumber;
}
}
one.start();
two.start();
double average = (one.getResult() + two.getResult()) / 2.0;
In Java 8 you can do
IntStream.of(0, 2).parallel()
.map(i -> new Random().nextInt(100)+1)
.forEach(System.out::println);
Without using the Stream API you can do
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 2; i++)
futures.add(ForkJoinPool.commonPool()
.submit(new Callable<Integer>() {
public Integer call() {
return new Random().nextInt(100)+1;
}));
for(Future<Integer> future : futures)
System.out.printl(future.get());
Here is the simple snippet to customize:
// 1. Create and fill callables to execute
List<Callable<Integer>> callables = new LinkedList<>();
// callabels.addAll(makeMeCallables());
// 2. Run using Executor of your choice
ExecutorService service = Executors.newCachedThreadPool();
List<Future<Integer>> results = service.invokeAll(callables);
// 3. Get the results
if (results.get(i).isDone()) {
Future f = result.get(i);
// process f.get()
}

Synchronized doesn't help to achieve mutual exclusion

Class C:
class C extends Thread
{
public static int cr;
C(int n)
{
cr = n;
}
public void run()
{
go();
}
synchronized void go()
{
for (int i = 0; i < 10000; i++)
{
cr++;
}
}
}
Class Launch
class Launch
{
public static void main(String args[]) throws InterruptedException
{
C[] c = new C[10];
for (int i = 0; i < 10; i++)
{
c[i] = new C(0);
}
for (int i = 0; i < 10; i++)
{
c[i].start();
}
System.out.println(C.spaces);
}
}
It doesn't give me 100,000, but rather numbers below 100k. Why? I made method go() synchronized, so it should be used by only one thread at a time..? What am I missing?
synchronized void go(){...} means that it is synchronized on current instance (on this). Since this method belongs to your custom Thread class and you are crating 10 threads there exist 10 different this references.
That is one of the reasons it is preferred to not extend Thread class, but to implement Runnable interface and pass instance of this interface to as many threads as you want.
Another problem is that you are printing edited value without waiting for threads to finish.
What you need is creating one instance which will hold value you want to change and invoke synchronized method from only one instance, because as mentioned by default synchronized void method is synchronized on this (current object on which this method is invoked).
class MyTask implements Runnable {
public volatile int counter;
MyTask(int n) {
counter = n;
}
public void run() {
System.out.println(Thread.currentThread().getName()+" entered run");
go();
System.out.println(Thread.currentThread().getName()+" finished run");
}
synchronized void go() {
System.out.println(Thread.currentThread().getName()+" entered go");
for (int i = 0; i < 10000; i++) {
counter++;
}
System.out.println(Thread.currentThread().getName()+" left from go");
}
}
class Luncher {
public static void main(String args[]) throws InterruptedException {
//lets create task we want to execute in parallel
MyTask task = new MyTask(0);
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++)//create thread instances
threads[i] = new Thread(task);
for (int i = 0; i < 10; i++)//start threads
threads[i].start();
for (int i = 0; i < 10; i++)
threads[i].join();//hold main thread to wait till all threads will finish
System.out.println(task.counter);
}
}
with
c[i] = new C(0);
you are creating new instance of c every time
with
synchronized void go()
{
for (int i = 0; i < 10000; i++)
{
cr++;
}
}
you will always get the number less than 10000 i dont know why you are expecting 100,000
Is it a typo mistake i < 10000 where you should have u used 100,000 ?
To answer your last question
I made method go() synchronized, so it should be used by only one thread at a time..?
if only one thread at a time, you don't need synchronized(multithreading concept).
It doesn't give me 100,000, but rather numbers below 100k. Why?
Every thing is working fine but main thread is not waiting for other threads to complete the calculation hence output is random in main thread.
Use Thread#join() so that main thread waits for all the other threads to die before executing the last line of the main thread.
for (int i = 0; i < 10; i++) {
c[i].start();
c[i].join(); // Waits for this thread to die
}
System.out.println(C.cr); // output 100000
It's worth reading How do I pause main() until all other threads have died?

Categories