'How to make threads compete against each other?

I'm currently programming a program for university. In this program I have to create three Consumerthreads which compete around a stock of products.

For the stock of products, I used a HashMap<String, Integer> which is saved in a class called marketplace.

My Consumer thread:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class consumer implements Runnable{

    List<String> productTypes = new ArrayList<>();
    Map<String, Integer> productsBought = new HashMap<>();
    marketplace marketplace;

    public consumer( marketplace marketplace) {
        this.marketplace = marketplace;
    }

    @Override
    public void run() {
        buy();
        this.marketplace.addProductsBought(this.productsBought);
    }

    public synchronized void buy(){
        int bought =0;
        this.productTypes = this.marketplace.getProductTypes();
        for(int i = 0; i<this.productTypes.size(); i++){
            String productType = this.productTypes.get(i);
            bought = this.marketplace.buyProduct(productType);
            this.productsBought.put(productType, bought);
        }
    }
}

Now to my question, how can I program the threads in a way that they really compete around the product, because when I initialize the threads, the first one buys everything and the others get nothing.

The Threads are started like:

Runnable consumerOne = new consumer(marketplace);
Runnable consumerTwo = new consumer(marketplace);
Runnable consumerThree = new consumer(marketplace);

Thread consumerOneThread = new Thread(consumerOne);
Thread consumerTwoThread = new Thread(consumerTwo);
Thread consumerThreeThread = new Thread(consumerThree);

consumerOneThread.start();
consumerTwoThread.start();
consumerThreeThread.start();

There are 6 different types of products in random amounts from 5 to 10 saved in the HashMap in the marketplace object.

Threadpools are not allowed.



Solution 1:[1]

Sleep

Looks like your first task completes before the later tasks have a chance.

To simulate real buyers, introduce some random amount of time for each buying task to wait.

int millis = ThreadLocalRandom.current().nextInt( 5 , 1_000 ) ;
Thread.sleep( millis ) ;

And you need your main thread to wait until tasks are done — see next section of this Answer to learn about using ExecutorService#awaitTermination to wait for completion.

Executors

By the way, in modern Java we rarely need to address the Thread class directly. Instead, use the Executors framework added to Java 5.

ExecutorService es = Executors.newFixedThreadPool( 3 ) ;
List< Consumer > tasks = … 
es.invokeAll( tasks ) ;
…

See more code examples in my Answer I wrote yesterday on a similar Question. And search Stack Overflow to learn more, as executor services has been covered many many times already.

Other issues

I don’t see why you have synchronized on the Consumer#buy method. The Consumer class has no concurrency issues since you instantiate one per thread.

Perhaps you are using that as a way to make your Marketplace class thread-safe. If so, that is misplaced responsibility. Classes should generally be responsible for themselves, not others. You should rewrite Marketplace to attend to its own concurrency needs.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1