I practice working with synchronization of threads and can’t do it the way I’ve come up with it. I have a bank account, my husband and wife put money in there. I want to make them take turns doing it. I do it like this:

public class Main { public static void main(String[] args) { new Wife().start(); new Husband().start(); } } public class Husband extends Thread{ @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { System.out.println("Husband " + i + " " + Account.deposit()); } } } public class Wife extends Thread{ @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { System.out.println("Wife " + i + " " + Account.deposit()); } } } public class Account { public synchronized static int deposit(){ account += 300; return account; } } 

But it still turns out to be a mess. Maybe instead of synchronized you need to use semaphores? So that was the correct sequence.

  • Schaub did it in turn - it seems that in wife and husband methods run enough to write Account.deposit() and in main write a for (int i = 0; i < 10; i++) { wife.start.... husband.start.....husband.join() } loop for (int i = 0; i < 10; i++) { wife.start.... husband.start.....husband.join() } ......... here's an example ideone.com/Fqe5g8 - Alexey Shimansky
  • And why push the creation of a stream into a loop, it will create a new stream 10 times ... Or do I not understand it so? - Aleksey Timoshchenko
  • and what is terrible here?))) created a stream, it quickly worked, died ...... went to another run-created -omer ... - Alexey Shimansky
  • That does not)) need to do so that it all ran in 2 streams Wife and Husband - Aleksey Timoshchenko
  • You can see the JavaSpecialist Newsletter 188 . There are two examples: using two semaphores, and a busy-wait on a volatile field. The latter works much faster than different blocking solutions (the faster, the simpler the executable code), but the processor eats badly. - zRrr

3 answers 3

Now there is no opportunity to think about an elegant solution, but I would ask the priorities. Here is a solution to the forehead:

 public class App { public static void main(String[] args) { Account account = new Account(0); new Wife(account).start(); new Husband(account).start(); } public static abstract class FamilyMember extends Thread { protected Account mAccount; protected String mId; public FamilyMember(Account account) { mAccount = account; } @Override public void run() { super.run(); startMe(); } protected abstract void startMe(); } public static class Husband extends FamilyMember { public Husband(Account account) { super(account); mId = getClass().getName(); mAccount.registerMember(getClass().getName()); } @Override protected void startMe(){ for (int i = 0; i < 10; i++) { try { while(!mAccount.CheckPriority(mId)) Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Husband " + i + " " + mAccount.deposit(mId)); } } } public static class Wife extends FamilyMember { public Wife(Account account) { super(account); mId = getClass().getName(); mAccount.registerMember(getClass().getName()); } @Override protected void startMe(){ for (int i = 0; i < 10; i++) { try { while(!mAccount.CheckPriority(mId)) Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Wife " + i + " " + mAccount.deposit(mId)); } } } public static class Account { private int mAccount = 0; private List<Member> mMembers = new ArrayList<App.Account.Member>(); /** * проверяем имеет ли член семьи максимальный приоритет * @param id * @return */ public synchronized boolean CheckPriority(String id){ Member member = mMembers.stream().max(Comparator.comparingInt(Member::getPriority)).get(); return member.getId().equals(id); } public void registerMember(String id){ mMembers.add(new Member(id, 0)); } public Account(int account) { mAccount = account; } public synchronized int deposit(String id) { mAccount += 300; // понижаем приоритет mMembers.stream().filter(member -> member.mId.equals(id)).findFirst().get().decPriority(); return mAccount; } public static class Member{ public String mId; public int mPriority; public Member(String id, int priority){ mId = id; mPriority = priority; } public void decPriority(){ mPriority--; } public int getPriority(){ return mPriority; } public String getId(){ return mId; } } } } 

Displays:

 Wife 0 300 Husband 0 600 Wife 1 900 Husband 1 1200 Wife 2 1500 Husband 2 1800 Wife 3 2100 Husband 3 2400 Wife 4 2700 Husband 4 3000 Wife 5 3300 Husband 5 3600 Wife 6 3900 Husband 6 4200 Wife 7 4500 Husband 7 4800 Wife 8 5100 Husband 8 5400 Wife 9 5700 Husband 9 6000 

Flows, before CheckPriority money into an account, check their priority using CheckPriority . If the current thread has a higher priority, mAccount.deposit(mId) and the current priority is lowered.

 mMembers.stream().filter(member -> member.mId.equals(id)).findFirst().get().decPriority(); 

Otherwise, falls asleep for 1ms.

  • Is it really unacceptable in Java to play with priorities? It seems fraught. different operating systems react differently to the priority of flows .... Instead of priority, can it be easier to keep one in the aka who last made the money and if people do not match - skip? - Alexey Shimansky
  • one
    @ Alexey Shimansky I do not change the priority of the thread. I am changing a variable that is similar in meaning to priority. - Suvitruf

Synchronization example using wait () / notify () :

 public class Main { public static void main(String[] args) { Account account = new Account(); new Thread(new Wife(account)).start(); new Thread(new Husband(account)).start(); } } public class Account { private int account; public boolean turn; public synchronized int deposit() { turn = !turn; account += 300; return account; } } public abstract class FamilyMember implements Runnable { private final String name; protected final Account account; public FamilyMember(String name, Account account) { this.name = name; this.account = account; } public abstract boolean isMyTurn(); public void run() { for (int i = 0; i < 10; i++) { synchronized (account) { while (!isMyTurn()) { try { account.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name + " " + i + " " + account.deposit()); account.notify(); } } } } public class Wife extends FamilyMember { public Wife(Account account) { super("Wife", account); } @Override public boolean isMyTurn() { return !account.turn; } } public class Husband extends FamilyMember { public Husband(Account account) { super("Husband", account); } @Override public boolean isMyTurn() { return account.turn; } } 

The invoice holds the turn flag, which determines which turn it is to deposit money. The shared code has moved to the FamilyMember class, the husband and wife wait in line using the isMyTurn() method.

Of course, it was clumsy, but it gives an idea of ​​using wait() and notify() .


This solution is similar to the solution of Suvitruf , but instead of Thread.sleep() , wait() used to wait() until the condition is met, which is more efficient because the program sleeps better. The notify() method notifies you of a condition change and wakes up the waiting thread.

wait() must be used in a loop, because the thread can wake up without calling notify() .


Instead of the flag account.turn , you can probably use the value of the account. If the amount on the account has changed, then the turn to put the money goes to another. To do this, you will need to add a synchronized method Account.get() , which will return the current amount in the account. The husband / wife memorizes the amount in the account after they have deposited the money and waits for the amount to change.

    It is possible and semaphores. If synchronized then you need to use the wait() / notify() construct: the husband makes a contribution — the wife “sleeps”, the wife makes a contribution — the husband falls asleep.

    • one
      Can I have some code? Here let's say on this site ideone.com - Aleksey Timoshchenko
    • Still, in this case, an object will be needed through which the turn will be transmitted. - Alexey Ivanov