Writing to / Reading from a vector (or ArrayList) with two streams

I have two threads, both of which refer to Vector. t1 adds a random number, and t2 removes and prints the first number. Below is the code and output. t2 seems to be executed only once (before t1 starts) and ends forever. Am I missing something? (PS: Tested also with ArrayList)

import java.util.Random; import java.util.Vector; public class Main { public static Vector<Integer> list1 = new Vector<Integer>(); public static void main(String[] args) throws InterruptedException { System.out.println("Main started!"); Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("writer started! "); Random rand = new Random(); for(int i=0; i<10; i++) { int x = rand.nextInt(100); list1.add(x); System.out.println("writer: " + x); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("reader started! "); while(!list1.isEmpty()) { int x = list1.remove(0); System.out.println("reader: "+x); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); t2.start(); t1.start(); t1.join(); t2.join(); } 

} Conclusion: The main thing has begun! The reader has begun! the writer has begun! writer: 40 writer: 9 writer: 23 writer: 5 writer: 41 writer: 29 writer: 72 writer: 73 writer: 95 writer: 46

+5
source share
3 answers

It sounds like a toy to understand concurrency, so I haven't mentioned this before, but now I (upstairs, because it matters).

If it is intended for production code, do not collapse your own. There are many well-implemented (debugged) parallel data structures in java.util.concurrent. Use them.


When consuming, you do not need to disconnect your consumer based on "all items consumed." This is due to the state of the race, when the consumer can “move forward” the manufacturer and find an empty list only because the manufacturer has not yet written items for consumption.

There are several ways to shut down a consumer, but none of them can be done by viewing the data that will be consumed in isolation.

My recommendation is that the manufacturer "signals" the consumer when the manufacturer produces. Then the consumer will stop when he has both a “signal” and no more data, and the list is empty.

Alternative methods include creating a shutdown element. The producer adds a shutdown element, and the consumer only shuts down when the shutdown element is displayed. If you have a consumer group, keep in mind that you should not remove the shutdown item (or only one user will disconnect).

In addition, the consumer could “control” the producer, so if the producer is alive / alive and the list is empty, the consumer assumes that more data will become available. The shutdown occurs when the manufacturer is dead / does not exist and there is no data.

Which method you use will depend on the approach you choose and the problem you are trying to solve.


I know that people love elegant solutions, but if your only manufacturer knows about one consumer, the first option looks.

 public class Producer { public void shutdown() { addRemainingItems(); consumer.shutdown(); } } 

where the consumer looks like {

 public class Consumer { private boolean shuttingDown = false; public void shutdown() { shuttingDown = true; } public void run() { if (!list.isEmpty() && !shuttingDown) { // pull item and process } } } 

Please note that such a lack of blocking of elements in the list is inherently dangerous, but you have indicated only one consumer, so there are no complaints about reading from the list.

Now, if you have several consumers, you need to provide protection to ensure that one element will not be pulled by two threads at the same time (and it needs to exchange data in such a way that all flows are disconnected).

+4
source

I think this is a typical consumer-producer problem . Try a look at Semaphore .

0
source

Update: the problem disappeared after changing the while loop in the consumer (reader). Instead of exiting the stream, if the list is empty, it now enters the loop, but does nothing. Below is an updated stream of readers. Of course, a decent shutdown mechanism, for example, proposed by Edwin, can be added to the code.

  public void run() { System.out.println("reader started! "); while(true) { if(!list1.isEmpty()) { int x = list1.remove(0); System.out.println("reader: "+x); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } 

Please note that this is not a piece of code taken from a real product, or it will go into one!

0
source

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


All Articles