Sharing an ArrayList between two threads?

So, I have two streams in which one of them should receive information from the user, and the other stream should work with the information provided by users, as follows:

public class UserRequest implements Runnable { @Override public void run() { // TODO Auto-generated method stub String request; Scanner input = new Scanner(System.in); while(true) { System.out.println("Please enter request:"); request = input.nextLine(); try { //do something } catch(IOException e) { e.printStackTrace(); } } } 

And the second thread:

 public class Poller implements Runnable { ArrayList<String> colors = new ArrayList<String>(); public void poll() { for(String color : colors) { if(color == "") { //do work } else { //do work } } } @Override public void run() { colors.add("Violet"); colors.add("Green"); colors.add("Yellow"); colors.add("Orange"); while(true) poll(); } } 

What I would like to do is take any input entered by the user inside the UserRequest object and click on the ArrayList in Poller object so that it can "work" with the new value. I looked at something like BlockingQueue , but I don't want any Thread to expect another, as they have other tasks that they need to perform in addition to this data sharing. How can i do this?

+5
source share
5 answers

Since you used the verbs "push" and "poll", it seems that you are looking for Queue not a List .

Therefore, I think you are looking for the ConcurrentLinkedQueue registered here .

This allows you to supply your UserRequest objects UserRequest it and your Poller objects for use.

Although it seems that your Poller objects will have a rather high processor load due to the open while not having wait :

 public class Poller implements Runnable { Queue<String> colors = new ConcurrentLinkedQueue<String>(); public void poll() { while(this.colors.isEmpty()){ Thread.currentThread().wait(); } String color = this.colors.poll(); while(color != null) { if(color == "") { //do work } else { //do work } color = this.colors.poll(); } } @Override public void run() { colors.offer("Violet"); colors.offer("Green"); colors.offer("Yellow"); colors.offer("Orange"); while(true) { this.poll(); } } } 

This code needs some changes to run , but it contains almost everything you need. What he does is very simple: he continues the survey until there are no elements left. As soon as this happens, the Poller object asks the current Thread sleep, since it makes no sense to run it without elements in Queue .

 public class UserRequest implements Runnable { @Override public void run() { String request; Scanner input = new Scanner(System.in); while(true) { System.out.println("Please enter request:"); request = input.nextLine(); try { //do something } catch(IOException e) { e.printStackTrace(); } finally { this.notifyAll(); // Notifies all sleeping threads to wake up } } } 

If you notice, I only added a call to notifyAll to your UserRequest class. What for? Very simple: notifyAll wakes up all wait ing Thread , which makes all Poller without elements.

As soon as it is called, Poller will wake up, check if they have Queue color elements and work with them. If Queue has no elements, they will sleep again until a UserRequest them again, etc. Etc.

+5
source

There are two ways to solve this problem:

1) It uses a thread safe collection , like ConccurentLinkedQueue for logic with producer-consumer, consumption of jobs, etc. If you want to use a class that implements the List interface (and, as a result, you can apply the same methods to usually an ArrayList ), you should look towards CopyOnWriteArrayList , but note that this class uses synchronization lock.

2) Another approach is to use the built-in Java synchronization tools, for example

You should read the specification for more details. Consider an example of using Semaphore:

 private final Semaphore semaphore = new Semaphore(2, true); public void appendToList() throws InterruptedException { available.acquire(); arrayList.add(.....); //put here what u need } public void putItem(Object x) { if (someLogicHere(x)) //semaphore releases counter in this place available.release(); } 

Of course, you can combine the use of all of them, for example. you can use several semaphores at the same time or use diff tools.

+3
source

"but I don’t want one Thread to expect another, because they have other tasks that they need to complete in addition to this data sharing.

Impossible to do this. Any proper threading of a class will always suffer from a problem that you will need for one thread to wait and another to expect something. The fact is that you want to minimize this. You want the thread to hang very briefly and rarely, and only in cases where this does not happen, it will lead to its failure. You can use one of the synchronized data structures or just write some synchronization code yourself.

The only object in question is an arraylist, and you want the absolute minimum number of stalls in any thread. Therefore, you want to synchronize it based on the object of the array itself. So just write a couple of small sync blocks around the points where you are accessing the arraylist object.

 public class Poller implements Runnable { ArrayList<String> colors; public Poller(ArrayList<String> colors) { this.colors = colors; //pass in colors object, if modified from the scanner side it must synchronize the block around the colors object too. } public void doWork(String color) { //do work } public void addColor(String color) { synchronized (colors) { colors.add(color); } } @Override public void run() { while (!Thread.interrupted()) if (!colors.isEmpty()) { String color; synchronized (colors) { color = colors.remove(0); } doWork(color); //work done outside synch } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } 

A point simply never deletes or adds things to the list at the same time. You cannot iterate over the list as a whole because if the work is done in a loop, the problem and the size of the array can change, so you don't know how much this bit is. But for this, you can use ArrayList to simply synchronize blocks of code in which you change the data structure and extract a row from this synchronized block, and then do work on it. Thus, the only stall is a short instant stream that reads or writes, and another is needed. Both operations are very fast.

+1
source

If you want to access the new value entered by the user from the poller object, then:

  • Since objects are stored on the heap, instead of creating a new instance of arrayList in the Poller class, you can simply send the list object reference from UserRequest. So when yu change adds a new value to the arrayList in userRequest, it will be reflected in the arrayList used by Poller.

For example, you can do this as follows:

  public class UserRequest implements Runnable { private ArrayList<String> arrayList = new ArrayList<String>(); @Override public void run() { // TODO Auto-generated method stub String request; Scanner input = new Scanner(System.in); while(true) { System.out.println("Please enter request:"); request = input.nextLine(); try { Poller poller = new Poller(arrayList); Thread t = new Thread(poller); t.start(); } catch(IOException e) { e.printStackTrace(); } } } 

You can change your Poller class as follows:

  public class Poller implements Runnable { private ArrayList arrayList = null; Poller(ArrayList<String> arrayList){ this.arrayList = arrayList; } public void poll() { for(String color : arrayList) { if(color == "") { //do work } else { //do work } } } @Override public void run() { while(true){ poll(); } } 

But instead of calling the pool in an infinite loop, you should add a listener to your array so that you only call poll() when a new value has been added to the list.

You can check this link to learn more about adding a listener to ArrayList : fooobar.com/questions/368956 / ...

0
source

You can use the queue. The queue has its own polling method. You can make it static, but I doubt this is the best approach. I usually use spring to create a queue in some kind of wrapper class, but it doesn't look like you take this route.

0
source

Source: https://habr.com/ru/post/1258994/


All Articles