Java: Communication between threads restricted to a method - java

I have to create a method to calculate the sum of all elements in an array. The caveat is that the array is divided into a number of parts for many threads to calculate these parts simultaneously, and then combine to calculate the sum
All of these are restricted to inside the method code. The problem is when I write:
Thread t = new Thread(()->{
int sum=0;
//do some calculations
//time to pass this result back to the main method
});
The local anonymous class can only access final or effectively final local variable of the main method, which means I can't create a local variable and then change it to update the result. I can't think of a way to pass a thread's result back to combine with the results from the other threads.
Is there any way to solve this?

You can divide up the work in your main thread and do something like this:
public class Foo implements Runnable {
private volatile CustomArray<Integer> arr;
private volatile Integer sum;
public Foo(CustomArray<Integer> arr) {
this.arr = arr;
}
#Override
public void run() {
synchronized(this.arr) {
sum = arr.getSum();
}
}
public Integer getValue() {
synchronized(this.arr) {
return sum;
}
}
}
And call from another thread like so:
CustomArray<Integer> completeArray = new CustomArray<>(data);
ArrayList<CustomArray<Integer>> dividedArrays = completeArray.divideWork();
for(CustomArray<Integer> each : dividedArrays) {
Foo foo = new Foo(each);
new Thread(foo).start();
// ... join through some method
Integer value = foo.getValue();
}
Or, you can use an Executor and a Callable:
public void test() throws InterruptedException, ExecutionException
{
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Integer> callable = new Callable<Integer>() {
#Override
public Integer call() {
return 2;
}
};
Future<Integer> future = executor.submit(callable);
// returns 2 or raises an exception if the thread dies
Integer output = future.get();
executor.shutdown();
}

Related

ExecutorService thread safety

Let's say I have an instance of ExecutorService from one of Executors static factory methods.
If I submit a Callable where RetVal is not a thread-safe, locally instantiated object from some thread, do I need to worry about RetVals' integrity when I get() it from the same thread? People say that local variables are thread-safe, but I am not sure if it applies when you're returning a locally instantiated Object and receiving it from some other thread.
Here's an example similar to my situation:
ExecutorService executor = Executors.newFixedThreadPool(5);
Future<List<String>> fut = executor.submit(() -> {
List<String> ret = new ArrayList<>();
ret.add("aasdf");
ret.add("dfls");
return ret;
});
List<String> myList = fut.get();
In the above example, I'm retrieving an ArrayList that was created in a different thread--one created by executor. I don't think above code is thread safe but I was not able to find much information regarding my specific situation.
Now I tried the above code on my computer and it actually returned the expected result 100% of the time I tried it, and I even tried with my own implementation of an ExecutorService and so far I have only got the expected results. So unless I have gotten extremely lucky I am pretty sure it works but I'm not sure how.
I created a not thread-safe object in another thread and received it in another; shouldn't I have a chance to have received a partially constructed object--in my case a list that does not contain 2 strings?
Below is my custom implementation I made just to test. You can ignore the EType enum thingy.
class MyExecutor {
enum EType {
NoHolder, Holder1, Holder2
}
private ConcurrentLinkedQueue<MyFutureTask<?>> tasksQ;
private final Thread thread;
private final EType eType;
public MyExecutor(EType eType) {
eType = Objects.requireNonNull(eType);
tasksQ = new ConcurrentLinkedQueue<>();
thread = new Thread(new MyRunnable());
thread.start();
}
public <T> Future<T> submit(Callable<T> c) {
MyFutureTask<T> task = new MyFutureTask<T>(c, eType);
tasksQ.add(task);
return task;
}
class MyRunnable implements Runnable {
#Override
public void run() {
while (true) {
if (tasksQ.isEmpty()) {
try {
Thread.sleep(1);
continue;
} catch (InterruptedException ite) {
Thread.interrupted();
break;
}
}
MyFutureTask<?> task = tasksQ.poll();
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class MyFutureTask<T> implements RunnableFuture<T> {
final Callable<?> cb;
volatile Object outcome;
static final int STATE_PENDING = 1;
static final int STATE_EXECUTING = 2;
static final int STATE_DONE = 3;
final AtomicInteger atomicState = new AtomicInteger(STATE_PENDING);
final EType eType;
public MyFutureTask(Callable<?> cb, EType eType) {
cb = Objects.requireNonNull(cb);
eType = Objects.requireNonNull(eType);
}
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
throw new NotImplementedException();
}
#Override
public boolean isCancelled() {
return false;
}
#Override
public boolean isDone() {
return atomicState.get() == STATE_DONE;
}
#SuppressWarnings("unchecked")
#Override
public T get() throws InterruptedException, ExecutionException {
while (true) {
switch (atomicState.get()) {
case STATE_PENDING:
case STATE_EXECUTING:
// Thread.sleep(1);
break;
case STATE_DONE:
return (T)outcome;
default:
throw new IllegalStateException();
}
}
}
#Override
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
throw new NotImplementedException();
}
void set(T t) {
outcome = t;
}
#Override
public void run() {
if (atomicState.compareAndSet(STATE_PENDING, STATE_EXECUTING)) {
Object result;
try {
switch (eType) {
case NoHolder:
result = cb.call();
break;
case Holder1:
throw new NotImplementedException();
case Holder2:
throw new NotImplementedException();
default:
throw new IllegalStateException();
}
} catch (Exception e) {
e.printStackTrace();
result = null;
}
outcome = result;
atomicState.set(STATE_DONE);
}
}
}
}
class MyTask implements Callable<List<Integer>> {
#Override
public List<Integer> call() throws Exception {
List<Integer> ret = new ArrayList<>(100);
IntStream.range(0, 100).boxed().forEach(ret::add);
return ret;
}
}
The important thing is the happens-before relationship. From ExecutorService API docs:
Memory consistency effects: Actions in a thread prior to the
submission of a Runnable or Callable task to an ExecutorService
happen-before any actions taken by that task, which in turn
happen-before the result is retrieved via Future.get().
So you are safe to transfer a mutable object like this. The ExecutorService implementation transfers the object via some form of safe publication.
Obviously, don't update the object in the original thread after returning it.
If you were to communicate between threads by stashing in a shared non-volatile field, then that would be unsafe.
Thread safety becomes a concern when multiple threads try to access and modify the same state simultaneously.
Note that you will not get hold of the actual result from a Future until the task is finished (i.e. Future#get will not return until the task is finished).
In your first example, thread safety is not an issue because the a new object (while mutable) is created by one thread (the thread created by the Executor) and retrieved from the Future object once that thread has finished processing the task. Once the calling thread gets hold of the object, it cannot be modified by any other thread, because the creating thread no longer has access to the List.

Thread Pool task list update issue [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am trying to design a thread pool at my end in java. As per my design I am using a java's Linkedlist DS inside a main runner thread class to hold on to all the submitted tasks. This task list is getting updated from the main class wherein the main class is adding a tasks to the task list. Inside my main runner thread I am running a while loop and constantly checking for whether the LinkedList is not empty , and if it contains a task then i am retrieving the task and executing it.
The problem here is that I have added a task from my main method in to the task list and I can see the size of this task list to be 1 from main method but inside the runner thread when i print the size of task list object , it shows it as 0.
Need help figuring out what exactly is happening here.
public class ReusableThread<T> extends Thread{
private volatile Queue<Work<T>> tasks = new LinkedList<Work<T>>();
private Work<T> currentWork;
private class Work<T>{
Result<T> result;
Taskable<T> task;
public Work(Result<T> result, Taskable<T> task) {
this.result = result;
this.task = task;
}
}
#Override
public void run() {
while(true){
//System.out.println("ReusableThread.run()");
System.out.println("Inside thread : " + getTasks().size()); //This print 0
if(!tasks.isEmpty()){
currentWork = getWork();
T value = currentWork.task.run();
//currentWork.result.setValue(currentWork.task.run());
}
//currentWork.result.setComplete(true);
}
}
public Work<T> getWork() {
return tasks.remove();
}
public Queue<Work<T>> getTasks() {
return tasks;
}
public Result<T> submit(Taskable<T> task) {
Result<T> result = new Result<T>();
this.tasks.add(new Work<T>(result, task));
return result;
}
}
The main thread is as below :
public void test() throws InterruptedException {
int count = 0;
ReusableThread<Integer> rt = new ReusableThread();
rt.start();
Thread.sleep(1000);
System.out.println("Thread-"+ count +" starting");
Result<Integer> result = rt.submit(JavaUtils::task);
System.out.println("In main : " + rt.getTasks().size()); //This prints 1
}
I think there is a thread-safety problem. Specifically:
a LinkedList is not thread-safe, and
you are using the LinkedList object in rt.getTasks().size() without any synchronization.
This is sufficient to cause size() to return a stale value under some circumstances.
If you are going to rely on the semantics of volatile you need to do a proper analysis of the happens-before relationships for each write / read sequence that matters to thread safety. It is tricky.
My advice would be:
Don't use volatile. Use synchronized and/or an existing thread-safe data structure instead ... if you need to reinvent the wheel.
Don't reinvent the wheel. You could replace your thread pool with a single call Executors.singleThreadExecutor; see javadoc.
You're missing synchronize 'tasks', so two thread (main and ReusableThread) random access to tasks, so you will not know what happen, I've modified your code:
import java.util.LinkedList;
import java.util.Queue;
class Result<T> {
}
interface Taskable<T> {
T run();
}
class JavaUtils {
public static Integer task() {
return 1;
}
}
public class ReusableThread<T> extends Thread{
private volatile Queue<Work<T>> tasks = new LinkedList<Work<T>>();
private Work<T> currentWork;
private class Work<T>{
Result<T> result;
Taskable<T> task;
public Work(Result<T> result, Taskable<T> task) {
this.result = result;
this.task = task;
}
}
#Override
public void run() {
while(true){
//System.out.println("ReusableThread.run()");
synchronized (tasks) {
if (!tasks.isEmpty()) {
System.out.println("Inside thread : " + tasks.size()); //This print 0
currentWork = tasks.remove();
T value = currentWork.task.run();
//currentWork.result.setValue(currentWork.task.run());
}
}
//currentWork.result.setComplete(true);
}
}
public Work<T> getWork() {
synchronized (tasks) {
return tasks.remove();
}
}
public Queue<Work<T>> getTasks() {
synchronized (tasks) {
return tasks;
}
}
public int getTaskSize() {
synchronized (tasks) {
return tasks.size();
}
}
public Result<T> submit(Taskable<T> task) {
Result<T> result = new Result<T>();
synchronized (tasks) {
this.tasks.add(new Work<T>(result, task));
}
return result;
}
public static void test() throws InterruptedException {
int count = 0;
ReusableThread<Integer> rt = new ReusableThread();
rt.start();
Thread.sleep(10);
System.out.println("Thread-"+ count +" starting");
Result<Integer> result = rt.submit(JavaUtils::task);
System.out.println("In main : " + rt.getTaskSize()); //This prints 1
}
public static void main(String[] args) throws Exception {
test();
}
}
and you should add Thread.sleep() to while(true) loop, If don't you will get 100% cpu soon

Synchronized method does not work as expected

I have a variable which is shared by two threads. The two threads will do some operations on it. I don't know why the result of sharedVar is different every time I execute the program.
public class Main
{
public static int sharedVar = 0;
public static void main(String[] args)
{
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.start();
mt2.start();
try
{
// wait for the threads
mt1.join();
mt2.join();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
System.out.println(sharedInt); // I expect this value to be 20000, but it's not
}
}
The following is the class "MyThread"
public class MyThread extends Thread
{
private int times = 10000;
private synchronized void addOne()
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar ++;
}
}
#Override
public void run()
{
addOne();
}
}
The final result of sharedVar sometimes are 13735, 12508, or 18793; but never 20000, which is the result I expect. Another interesting thing about the program is when times=1000. I always get 2000 as the final result.
Can anyone explain this phenomenon?
A synchronized method protects the resource this that means that your code is equivalent to:
private void addOne()
{
synchronized(this)
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar ++;
}
}
}
But you have 2 objects for which addOne method is called. That means this for mt1.addOne is not the same than this for mt2.addOne and therefore you don't have a common resource of synchronization.
Try changing yout addOne code to:
private void addOne()
{
synchronized(MyThread.class)
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar ++;
}
}
}
And you will observe the expected behaviour. As the comments below suggest, it is better to use a different object than MyThread.class for synchronization since class objects are accesible from many points and it is easy that other code may try to synchronize using the same object.
When you use synchronized on non-static method, you use current object as monitor.
When you use synchronized on static method, you use current object of class (ClassName.class static field) as monitor.
In your case, you use synchronized on Thread's object (2 different instances), so two different threads will modify your sharedVar static field at same time.
You can fix it in different ways.
Move addOne method to Main and make it static.
private static synchronized void addOne(int times)
{
for (int i = 0; i < times; ++i)
{
sharedVar++;
}
}
Or you can create class called SharedVar with field private int var; and method synchronized void addOne(int times) and pass single instance of SharedVar to your treads.
public static void main(String[] args)
{
SharedVar var = new SharedVar();
MyThread mt1 = new MyThread(var);
MyThread mt2 = new MyThread(var);
mt1.start();
mt2.start();
try
{
// wait for the threads
mt1.join();
mt2.join();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
System.out.println(var.getVar()); // I expect this value to be 20000, but it's not
}
But if you need only one integer to be changed in multiple threads, you can use classes from java.til.concurrent.*, like AtomicLong or AtomicInteger.
Define sharedVar as an AtomicLong instead of int. Making the function synchronized works as well but it is less efficient because you only need the increment to be synchronized.
When a thread is about to execute a 'synchronized' instance method, it aqcuires the lock on the Object(to be precise, lock on that object monitor).
So in your case, Thread mt1 acquires lock on Object mt1 and Thread mt2 acquires lock on Object mt2 and they do not block each Other as the two threads are working on two different locks.
And when two threads modify a shared variable concurrently(not synchronized way), the result is unpredictable.
Well about the case of value 1000, for smaller inputs the interleaved execution might have resulted in correct result(luckily).
Sol : remove the synchronized keyword from addOne method and make sharedVal as type of 'AtomicInteger'
Join the thread immediately after start method. From this thread-1 will start and go to dead state after that thread-2 will start and go to dead state. So it will print your expected output always.
Change the code as shown below:-
public class Main{
public static int sharedVar = 0;
public static void main(String[] args)
{
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
try
{
mt1.start();
mt1.join();
mt2.start();
mt2.join();
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
System.out.println(sharedVar);
}
}
class MyThread extends Thread
{
private int times = 1000000;
private synchronized void addOne()
{
for (int i = 0; i < times; ++i)
{
Main.sharedVar++;
}
}
#Override
public void run()
{
addOne();
}
}

How to synchronize two methods

I have following code for a chat server application in Java -
public synchronized List<ChatMessage> getMessages(int messageNumber) {
return messages.subList(messageNumber + 1, messages.size());
}
public synchronized int addMessage(ChatMessage c) {
messages.add(c);
return messages.size()-1;
}
I have following test code -
public static void main(String[] args) {
final ChatRoom c = new ChatRoom();
Thread user1 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++) {
c.addMessage(new ChatMessage());
c.getMessages(0);
}
}
});
Thread user2 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++) {
c.addMessage(new ChatMessage());
c.getMessages(0).size();
}
}
});
user1.start();
user2.start();
}
I am getting a ConcurrentModificationException.
How is this possible?
How is this possible?
Your getMessages method just returns a view on the original list. It doesn't create a copy of the list. So one thread is using a view on the list while another modifies the list - at that point, you get the exception.
From the docs for List.subList:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
It's not clear what you're really trying to achieve here, but fundamentally you can't use subList to magically create a thread-safe list :)
The simplest thing to do is to create a combined method
public synchronized int addMessageAndGetCount(ChatMessage c) {
messages.add(c);
return messages.size();
}
public static void main(String... args) {
final ChatRoom c = new ChatRoom();
final Runnable runner = new Runnable() {
public void run() {
for(int i = 0; i < 1000; i++) {
c.addMessageAndGetCount(new ChatMessage());
}
}
};
new Thread(runner).start();
new Thread(runner).start();
}
You cannot safely return a list or a subList from a synchronized block. You can return a copy but all you need is the size.

IlleagalMonitorStateException when I am trying to run this program

public class ThreadTest
{
public static Integer i = new Integer(0);
public static void main(String[] args) throws InterruptedException
{
ThreadTest threadTest = new ThreadTest();
Runnable odd = threadTest.new Numbers(1, "thread1");
Runnable even = threadTest.new Numbers(0, "thread2");
((Thread) odd).start();
((Thread) even).start();
}
class Numbers extends Thread
{
int reminder;
String threadName;
Numbers(int reminder, String threadName)
{
this.reminder = reminder;
this.threadName = threadName;
}
#Override
public void run()
{
while (i < 20)
{
synchronized (i)
{
if (i % 2 == reminder)
{
System.out.println(threadName + " : " + i);
i++;
i.notify();
}
else
{
try
{
i.wait();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
You can't synchronize on i because it changes during execution of your program.
Since Integer in Java is immutable, after executing i++ i will contain a reference to another object, not the object you have synchronized on. So, you can't call wait()/notify() on this new object, because these methods may be only called on the object you are synchronized on, otherwise you get IllegalMonitorStateException.
You need to synchronize on some other object that doesn't change during execution. For example, you may create a separate object for this purpose:
public class ThreadTest {
public static Integer i = new Integer(0);
public static Object lock = new Object();
...
class Numbers extends Thread {
...
#Override
public void run() {
...
synchronized (lock) {
...
lock.notify();
...
lock.wait();
...
}
}
}
}
This line:
i++;
is equivalent to:
i = i + 1;
which (due to autoboxing) becomes something like:
i = new Integer(i.intValue() + 1);
So, when you call i.notify() you are synchronized on the old i, not the new one.
I'd suggest changing i into an ordinary int variable, and create a separate object to synchronize on:
static int i = 0;
static Object iMonitor = new Object();
As documentation states the exception is thrown when
the current thread is not the owner of the object's monitor
It also states that
This method should only be called by a thread that is the owner of this object's monitor.
And this condition can be obtained by
By executing a synchronized instance method of that object.
By executing the body of a synchronized statement that synchronizes on the object.
For objects of type Class, by executing a synchronized static method of that class.
You could try calling the wait method from inside the class that uses i. This could be done by extending the class and writing two new methods for notify and wait..
You cannot put wait() and notify() in the same synchronized block because that will just cause a deadlock. Make sure only the wait and notify functions are wrapped with a synchronized block like this:
synchronized (i) {
i.wait(); // or i.notify();
}

Categories

Resources