Good day. In the process of writing a program in Java using threads, I ran into a problem. The program started 8 threads at once. Each thread should display messages like:

1 Andrew Removed from the account 98 Now for the account: 4902

where the first digit is:

private int id = 1; 

and access to it is realized through

 public synchronized int idPlus() { return id++; } public synchronized int getId() { return id; } 

part of the code of the executed thread:

  bank.putOn(currsumm); String s = getId() + " " + Thread.currentThread().getName() + " Положил на счёт " + currsumm + " Cейчас на счёту: " + bank.getBalance(); System.out.println(s); idPlus(); 

But when I run the program, the variable id with the same value can pop up several times. And it turns out that something like this:

1 Boris Withdrawn from 106 Now on the account: 4751

1 Galya Withdrawn from account 63 Now on the account: 4751

1 Valentin Withdrawn from the account 80 Now for the account: 4751

1 Andrew Put at the expense of 99 Now on the account: 4850

Already declared the id volatile variable and called join () on the threads; What can you suggest with on this issue?

All code: https://ideone.com/MygrDN

    2 answers 2

    That you do not quite understand the principles of multithreading and synchronization methods. If I understand correctly what you want to do, then you need something like this:

     bank.putOn(currsumm); synchronized (this) { String s = getId() + " " + Thread.currentThread().getName() + " Положил на счёт " + currsumm + " Cейчас на счёту: " + bank.getBalance(); System.out.println(s); idPlus(); } 

    And remove synchronized from methods. BUT! This will be the wrong decision, because in fact the program will turn into a single-threaded, because All operations will go sequentially in different streams, and not in parallel as you probably would like.

    For you, the right solution would be to increase the ID value right in the method that returns this value. And at the same time use not int , but Integer to return a new object, and not a link to the one that can be changed from another thread. Those. there must be something like this:

     private Integer id = 1; public synchronized Integer getId() { return id++; } 
    • I don't want to remove synchronized from methods, I want each output id to be unique. With the replacement of int by Integer, nothing has changed. Or is it simply impossible if the streams will run parallel to each other? - Zawarudo
    • @Zawarudo idPlus instead of getId - Vladislav Pyatkov
    • In both methods, I replaced int with Integer - Zawarudo
    • @Zawarudo It is necessary not only to replace Integer, but the method of obtaining Id itself must be changed. - Vartlok
    • Yes, I did not immediately notice. Now everything works correctly, thanks for the reply. - Zawarudo

    The point here is that obtaining the value of the id variable and its increase are different operations, and the scheduler can suspend the flow at the moment when one operation was performed and the other has not yet begun. The synchronized block does not help here. In this situation, the id must be declared as AtomicInteger. And form the line as follows:

      bank.putOn(currsumm); String s = id.incrementAndGet() + " " + Thread.currentThread().getName() + " Положил на счёт " + currsumm + " Cейчас на счёту: " + bank.getBalance(); System.out.println(s);