Практикуюсь работать с синхронизацией потоков и не получается сделать так, как придумал. У меня есть аккаунт в банке, муж и жена кладут туда деньги. Я хочу сделать так, чтоб они по очереди это делали. Я делаю это так:
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;
}
}
Но все равно получается бардак. Может вместо synchronized нужно семафоры использовать? Чтоб была правильная очередность.
Ответ
Сейчас нет возможности обдумать элегантное решение, но я бы приоритеты задавал. Вот решение в лоб:
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
/**
* проверяем имеет ли член семьи максимальный приоритет
* @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;
}
}
}
}
Выведет:
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
Потоки, перед тем как внести деньги на счёт, проверяют свой приоритет с помощью CheckPriority. Если текущий поток имеет больший приоритет, то вносятся деньги mAccount.deposit(mId) и понижается текущий приоритет
mMembers.stream().filter(member -> member.mId.equals(id)).findFirst().get().decPriority();
Иначе засыпает на 1мс.
Комментариев нет:
Отправить комментарий