2

I am trying to learn multi-threading using the runnable interface but I am having some trouble figuring out how to pass information. Basically, in the example below, I want to remove the static reference from the Hashmap but if I do that, the program breaks. How do I pass the hashmap to the runnable interface class without using the static keyword?

public class ThreadDemo {

static HashMap <String, Integer>map = new HashMap<>();

public String Hi() {
    return "hi";
}

public String Hello() {
    return "Hello";
}

public void addToMap(String item) {
    if (map.containsKey(item)) {
        map.put(item, map.get(item) + 1);
    } else {
        map.put(item, 1);
    }
}


public static void main(String[] args) throws InterruptedException {

    ArrayList<Thread> all = new ArrayList<>();
    
    for (int i = 0; i < 50; ++i) {
        threader threader = new threader();
        all.add(new Thread(threader));
    }

    for (Thread thread : all) {
        thread.start();
    }
    
    for (Thread thread : all) {
        thread.join();
    }
    
    ThreadDemo td = new ThreadDemo();
    System.out.println(td.map);

    
}

}

And a class that implements Runnable

public class threader implements Runnable {

ThreadDemo td = new ThreadDemo();

@Override
public void run() {
    
    synchronized(td.map) {
        td.addToMap(td.Hi());
        td.addToMap(td.Hello());

    }
    
    
}

}

forkbun882
  • 115
  • 7

1 Answers1

2

A class instance is all about information.

public class threader implements Runnable {
   final private ThreadDemo td;

   public threader(ThreadDemo td) {
      this.td = td;
   }

   @Override
   public void run() {
     ..
   }

}

then to use (details omitted, just the idea):

ThreadDemo theTd = new ThreadDemo();
for (...) {
    threader threader = new threader(theTd);
    all.add(new Thread(threader));
}

....

Of course, all threads are using the same ThreadDemo, with the same map, so you'll need to ensure access is interlocked in some way, e.g., by using synchronized. The ThreadDemo.addToMap method should be synchronized in this example, rather than the caller of addToMap. This puts the responsibility for the "care of the map" into the place that actually owns the map, and is consequently a better design.

I chose to share the ThreadDemo rather than just the map inside the ThreadDemo, since it looks to me that the intent of ThreadDemo is just to be a wrapper around the map.

iggy
  • 1,328
  • 4
  • 3
  • could you explain why the addToMap method needs to be synchronized? – forkbun882 May 14 '21 at 02:38
  • 2
    There is a single hash map. The map is being accessed by 50 threads simultaneously. The [HashMap documentation](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html) tells us that it is not thread-safe. Therefore we have to arrange that only one thread actually touches the map at ant time. The only code that touches the map is addToMap, so the easiest solution (given we have that map) is to make addToMap synchronized - which means only one thread will be executing in it at a time. – iggy May 14 '21 at 02:44
  • I perhaps wasn't clear that I mean synch addToMap instead of the caller of addToMap. I updated my answer to add detail. – iggy May 14 '21 at 02:48