Search code examples
javamultithreadingarraylistsynchronizationrunnable

Synchronization of two method which work on ArrayList


I have Sum class, Creator class, Item class and Main. The Creator creates random Items and adds them to an ArrayList which is in the Item class. The Sum class reads items and sums the weight of all. In the Main class I start in multiple threads Creator and Sum. Both classes implement Runnable and override the run method. After 200 created are items into is printed in the console.

How to synchronize this methods? When I start threads, the method from Sum ends first and returns weight 0 and after that Creator creating 40 000 random Items. I will create items and at the same time Sum all weights of them and in the end Return how many items were created and weight of all of them.

Sum class method:

@Override
    public synchronized void run() {

        for(Towar x: Towar.list){
            try {
                Thread.currentThread().wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter++;
            sum+=x.getWaga();
            if(counter%100==0){
                System.out.println("Sum of "+counter+" items");
            }
        }
        System.out.println("Total weight of Items: "+sum);
    }

Creator class method:

@Override
    public void run() {
        reader=new Scanner(text);
        while(reader.hasNextLine()){
            counter++;
            String[] x=reader.nextLine().split("_");
            synchronized (Towar.getList()){
                Towar.add(new Towar(x[0], Integer.parseInt(x[1])));
                Towar.list.notify();
                if(counter%200==0){
                    System.out.println("Created "+counter+" items");
                }
            }

        }
        System.out.println("Created in total: "+counter+" items");
    }

Solution

  • BlockingQueue

    I would recommend using implementations of the BlockingQueue interface, instead of ArrayList. A BlockingQueue is thread-safe.

    To quote the Javadoc:

    BlockingQueue implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control. However, the bulk Collection operations addAll, containsAll, retainAll and removeAll are not necessarily performed atomically unless specified otherwise in an implementation. So it is possible, for example, for addAll(c) to fail (throwing an exception) after adding only some of the elements in c.

    Example code

     class Producer implements Runnable {
       private final BlockingQueue queue;
       Producer(BlockingQueue q) { queue = q; }
       public void run() {
            reader=new Scanner(text);
            while(reader.hasNextLine()){
                counter++;
                String[] x=reader.nextLine().split("_");
                q.put(new Towar(x[0], Integer.parseInt(x[1])));
                if(counter%200==0){
                  System.out.println("Created "+counter+" items");
                }
            }
            q.put(null);
            System.out.println("Created in total: "+counter+" items");
       }
     }
    
     class Consumer implements Runnable {
       private final BlockingQueue queue;
       Consumer(BlockingQueue q) { queue = q; }
       public void run() {
         long sum = 0;
         try {
           while (true) { 
              Towar x = (Towar)queue.take();
              if (x == null) return;
              counter++;
              sum+=x.getWaga();
              if(counter%100==0){
                    System.out.println("Sum of "+counter+" items");
              }
           }
         } catch (InterruptedException ex) { ... handle ...}
       }
     }