Java multithreading - Threadsafe counter

I start with a very simple multithreading example. I'm trying to make a ceiling counter. I want to create two threads that increment the counter intermittently to 1000. The code below:

public class ThreadsExample implements Runnable {
     static int counter = 1; // a global counter

     public ThreadsExample() {
     }

     static synchronized void incrementCounter() {
          System.out.println(Thread.currentThread().getName() + ": " + counter);
          counter++;
     }

     @Override
     public void run() {
          while(counter<1000){
               incrementCounter();
          }
     }

     public static void main(String[] args) {
          ThreadsExample te = new ThreadsExample();
          Thread thread1 = new Thread(te);
          Thread thread2 = new Thread(te);

          thread1.start();
          thread2.start();          
     }
}

From what I can tell, the while loop now means that only the first thread has access to the counter until it reaches 1000. Exit:

Thread-0: 1
.
.
.
Thread-0: 999
Thread-1: 1000

How to fix it? How can I get streams for sharing a counter?

+4
source share
4 answers

Both threads have access to your variable.

, , . (, ), , , ( , ). , , , java , . ( ) , , , .

Oracle:

Starvation , . , "" . , , , . , , .

"" ( ), -0, , -1.

, (, ReentrantLock), :

public class ThreadsExample implements Runnable {
    static int counter = 1; // a global counter

    static ReentrantLock counterLock = new ReentrantLock(true); // enable fairness policy

    static void incrementCounter(){
        counterLock.lock();

        // Always good practice to enclose locks in a try-finally block
        try{
            System.out.println(Thread.currentThread().getName() + ": " + counter);
            counter++;
        }finally{
             counterLock.unlock();
        }
     }

    @Override
    public void run() {
        while(counter<1000){
            incrementCounter();
        }
    }

    public static void main(String[] args) {
        ThreadsExample te = new ThreadsExample();
        Thread thread1 = new Thread(te);
        Thread thread2 = new Thread(te);

        thread1.start();
        thread2.start();          
    }
}

synchronized ReentrantLock . , , , , .

+11

AtomicInteger. , , , , .

public class ThreadsExample implements Runnable {
     static AtomicInteger counter = new AtomicInteger(1); // a global counter

     public ThreadsExample() {
     }

     static void incrementCounter() {
          System.out.println(Thread.currentThread().getName() + ": " + counter.getAndIncrement());
     }

     @Override
     public void run() {
          while(counter.get() < 1000){
               incrementCounter();
          }
     }

     public static void main(String[] args) {
          ThreadsExample te = new ThreadsExample();
          Thread thread1 = new Thread(te);
          Thread thread2 = new Thread(te);

          thread1.start();
          thread2.start();          
     }
}
+8

, , "" , Thread.yield() incrementCounter(), .

public void run() {
         while(counter<1000){
              incrementCounter();
              Thread.yield();

         }
    }

Otherwise, to get what you offer, you can create two different classes of threads (ThreadsExample1 and ThreadsExample2, if you want), and the other class a shared variable.

public class SharedVariable {
    private int value;
    private boolean turn; //false = ThreadsExample1 --> true = ThreadsExample2

    public SharedVariable (){
        this.value = 0;
        this.turn = false;
    }

    public void set (int v){
        this.value = v;
    }

    public int get (){
        return this.value;
    }

    public void inc (){
        this.value++;
    }

    public void shiftTurn(){
        if (this.turn){
            this.turn=false;
        }else{
            this.turn=true;
        }
    }

    public boolean getTurn(){
        return this.turn;
    }

}

Now the main one might be:

public static void main(String[] args) {
        SharedVariable vCom = new SharedVariable();
        ThreadsExample1 hThread1 = new ThreadsExample1 (vCom);
        ThreadsExample2 hThread2 = new ThreadsExample2 (vCom);

        hThread1.start();
        hThread2.start();

        try {
            hThread1.join();
            hThread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

And you have to change your line static int counter = 1; // a global counter forprivate SharedVariable counter;

And a new run:

public void run() {
    for (int i = 0; i < 20; i++) {
        while (!counter.getTurno()){
            Thread.yield();
        }
        System.out.println(this.counter.get());
        this.counter.cambioTurno();
    }
}

}

Yes, this is another code, but I think it can help you a little.

+1
source

try sleeping the thread to make sure the other one has access:

     @Override
     public void run() {
          while(counter<1000){
               incrementCounter();
               Thread.sleep(1);
          }
     }
0
source

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


All Articles