java monitor 用法_[作业解析]并发中的Monitor及在Java中的运用如notify(),synchronized等用法...

作业题目:

给定一个如下Java类Konto(即银行帐号),能实现存钱einzahlen和取钱auszahlen的功能。

/* Eine Klasse für Bankkonten, die noch nicht für den nebenläufigen Zugriff angepasst wurde */

import java.util.ArrayList;

import java.util.Random;

import java.util.HashMap;

class Konto {

// Kontonummer als String

public String kontonummer;

// Kontostand

public int kontostand;

// Konstruktor

Konto(String nummer, int einlage) {

this.kontonummer = nummer;

this.kontostand = einlage;

}

// getter-Methoden:

public int getKontostand() {

return this.kontostand;

}

public String getKontonummer() {

return this.kontonummer;

}

// Auszahlen

public void auszahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " auszahlen.");

kontostand = kontostandvorher - betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " ausgezahlt.");

}

// Einzahlen

public void einzahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " einzahlen.");

this.kontostand = kontostandvorher + betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " eingezahlt.");

}

}

// Klasse für nebenläufig-ablaufende Transaktion

class Transaktion implements Runnable {

private Konto konto;

private int betrag;

private boolean istAuszahlung; // true = Auszahlung, false = Einzahlung

public Transaktion(Konto konto, int betrag, boolean auszahlung) {

this.konto = konto;

this.betrag = betrag;

this.istAuszahlung = auszahlung;

}

public void run() {

if (istAuszahlung) {

// Auszahlen

konto.auszahlen(betrag);

}

else {

// Einzahlen

konto.einzahlen(betrag);

}

}

}

public class KontoSimulation {

public static void main(String[] args) {

// Ein Konto mit initialem Kontostand 10

Konto konto = new Konto("konto", 10);

Random rnd = new Random();

int checkExecution = konto.getKontostand();

ArrayList transaktionen = new ArrayList<>();

// Starte 10 Transaktionen

for (int i = 0; i < 10; ++i) {

int betrag = 1 + rnd.nextInt(100);

boolean auszahlung = rnd.nextBoolean();

transaktionen.add(new Thread(new Transaktion(konto,betrag,auszahlung)));

checkExecution = checkExecution + (auszahlung?(-1)*betrag:betrag);

}

// Starte Threads

for (Thread t : transaktionen) {

t.start();

// Auskommentieren für Sequentielle Simulation:

// try {t.join();} catch (InterruptedException e) {}

}

// Warte auf Beenden der Threads

for (Thread t : transaktionen) {

try {t.join();} catch (InterruptedException e) {}

}

// Prüfe Ergebnis:

System.out.println("Kontostand erwartet: " + checkExecution);

System.out.println("Tatsächlicher Kontostand: " + konto.getKontostand());

//

// Testprogramm fuer Aufgabenteil e):

//KontoSimulationFuerAufgabeE.main(args);

}

}

问题

a) 这个类还不能做到并发存取钱,请你通过运用Monitor实现,可以先写出伪代码

答:

比较简单,给几个方法加上synchronized 就行

/* Eine Klasse für Bankkonten, die noch nicht für den nebenläufigen Zugriff angepasst wurde */

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Random;

class Konto {

// Kontonummer als String

public String kontonummer;

// Kontostand

public int kontostand;

// Konstruktor

Konto(String nummer, int einlage) {

this.kontonummer = nummer;

this.kontostand = einlage;

}

// getter-Methoden:

public synchronized int getKontostand() {

return this.kontostand;

}

public synchronized String getKontonummer() {

return this.kontonummer;

}

// Auszahlen

public synchronized void auszahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " auszahlen.");

kontostand = kontostandvorher - betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " ausgezahlt.");

}

// Einzahlen

public synchronized void einzahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " einzahlen.");

this.kontostand = kontostandvorher + betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " eingezahlt.");

}

}

// Klasse für nebenläufig-ablaufende Transaktion

class Transaktion implements Runnable {

private Konto konto;

private int betrag;

private boolean istAuszahlung; // true = Auszahlung, false = Einzahlung

public Transaktion(Konto konto, int betrag, boolean auszahlung) {

this.konto = konto;

this.betrag = betrag;

this.istAuszahlung = auszahlung;

}

public void run() {

if (istAuszahlung) {

// Auszahlen

konto.auszahlen(betrag);

}

else {

// Einzahlen

konto.einzahlen(betrag);

}

}

}

/*//伪代码

* a) Monitor for Konto

* Monitor Konto {

* String kontonummer

* int Kontostand

* //Condition KontoVerfügbar;

* einzahlen(v){

* //waitC(KontoVerfügbar)

* saldo += v;

* //signalC(KontoVerfügbar)

* }

* auszahlen(v){

* //waitC(KontoVerfügbar)

* saldo -= v;

* //signalC(KontoVerfügbar)

* }

* }

* */

b)用一个条件变量ConditionVaribale kontostandErlaubt,表示账户余额足够,实现仅当余额大于-100时,才能从该账户中取钱。同样写出伪代码(这里Monitor中不同的队列 采用优先级EntryQ

/*

* MonitorB Konto {

* String kontonummer;

* int kontostand;

* condition kontostandErlaub

*

* void auszahlen(int betrag){

* if kontostand < -100 then

* wartC(kontostandErlaub)

* int kontostandVorher = getkontostand()

* kontostand = kontostand - betrag;

* if kontostand < -100 then

* signalC(kontostandErlaub) # 这步很重要,考虑下余额在-200的时候,连续两笔想取钱的操作都冻住了,这是时候来了一笔充值500的,是不是卡住的两个都应该能放行了,

* 但是没有这步的话,就只有一个能放行;又有人会问,如果不写这步,在einzahlen中用signalAllC代替行吗(即在java中用signalAll),我觉得也行。只要在auszahlen里面用始终用while代替if

* }

* void einzahlen(int betrag){

* int kontostandVorher = getkontostand()

* kontostand = kontostand + betrag

* if kontostand >= -100 then

* signalC(kontoStandErlaub)}

* }

* }

* */

// 如何保证E=W

// ,并且执行之后导致if中的条件事实上已经不满足了,但是wait中的线程依然会在之后被运行,因为它已经不在ConQ里面了,不用被判断了。

// 用了 while 是不是可以把 signalAll/signal 前面if给去掉了,是的,没啥区别

class Konto {

// Kontonummer als String

public String kontonummer;

// Kontostand

public int kontostand;

// Konstruktor

Konto(String nummer, int einlage) {

this.kontonummer = nummer;

this.kontostand = einlage;

}

// getter-Methoden:

public synchronized int getKontostand() {

return this.kontostand;

}

public synchronized String getKontonummer() {

return this.kontonummer;

}

// Auszahlen

public synchronized void auszahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " auszahlen.");

while (getKontostand() < -100){

try {wait();} catch (InterruptedException e) {return ;}

}

kontostandvorher = getKontostand();

kontostand = kontostandvorher - betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " ausgezahlt.");

if (getKontostand() >= -100){

notify();

}

}

// Einzahlen

public synchronized void einzahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " einzahlen.");

this.kontostand = kontostandvorher + betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " eingezahlt.");

if (getKontostand() >= -100){

notify();

}

}

}

c)由于是个小银行,对于账户余额中巨额存款要收手续费,为了避免手续费,我们再加一个ConditionVariable keineStrafzinsenFaellig,表示余额不至于过多,我们认为余额 >=1000即为巨额。同样写出伪代码和实现

// 如何保证E=W

// 答案是不行,entry 和 wait 同等级,用if 的话, 由于前面的signal, conditionQ 中的已经被移到waitQ里了,这时候如果插进来一个EntryQ中的线程(由于Entry优先级高)

// ,并且执行之后导致if中的条件事实上已经不满足了,但是wait中的线程依然会在之后被运行,因为它已经不在ConQ里面了,不用被判断了。

// 用了 while 是不是可以把 signalAll/signal 前面if给去掉了,是的,没啥区别

/* Monitor KontoC{

String kontonummer

int kontostand

condition kontoErlaub

condition keineStrafzinsenFaellig

void einzahlen(betrag){

if kontostand>=1000 then

wartC(keineStarfzinsenFaellig)

kontostand += betrag

if kontostand < 1000 then

signalC(keineStrafzinsenFaellig)

if kontostand >= -100 then

signalC(KontoErlaub)

}

void auszahlen(betrag){

if kontostand < -100 then

waitC(kontoErlaub)

kontostand -= betrag

if kontostand >= -100 then

signalC(kontoErlaub)

if kontostand < 1000 then

signalC(keineStrafzinsenFaellig)

}

}

*

* 由于Java 默认不支持多个 Condition Variable, 我们吧伪代码改成 适合 Java的版本, 用signalALLC/notifyAll(),就是所有困于CV的线程都能得到唤醒,都到WaitQ了,然后按顺序一个一个再次通过while检查,接着按顺序拿到锁(monitor的基本逻辑,只有一把锁)

* Monitor KontoCJava{

String kontonummer

int kontostand

condition CV

void einzahlen(betrag){

while kontostand>=1000 then

wartC(CV)

kontostand += betrag

if kontostand < 1000 then

signalAllC(CV)

if kontostand >= -100 then

signalAllC(CV)

}

void auszahlen(betrag){

while kontostand < -100 then

waitC(CV)

kontostand -= betrag

if kontostand >= -100 then

signalAllC(CV)

if kontostand < 1000 then

signalAllC(CV)

}

}

*/

/*

* Typical result:

* DEBUG: [Thread-0] möchte 788 vom Konto konto mit Kontostand 500 auszahlen.

DEBUG: [Thread-0] hat 788 vom Konto konto mit Kontostand -288 ausgezahlt.

DEBUG: [Thread-1] möchte 648 vom Konto konto mit Kontostand -288 auszahlen.

DEBUG: [Thread-1] get blocked

DEBUG: [Thread-3] möchte 346 vom Konto konto mit Kontostand -288 auszahlen.

DEBUG: [Thread-3] get blocked

DEBUG: [Thread-2] möchte 335 vom Konto konto mit Kontostand -288 auszahlen.

DEBUG: [Thread-2] get blocked

DEBUG: [Thread-4] möchte 206 auf das Konto konto mit Kontostand -288 einzahlen.

DEBUG: [Thread-4] hat 206 auf das Konto konto mit Kontostand -82 eingezahlt.

DEBUG: [Thread-2] activated

DEBUG: [Thread-2] hat 335 vom Konto konto mit Kontostand -417 ausgezahlt.

DEBUG: [Thread-3] activated

DEBUG: [Thread-3] get blocked

DEBUG: [Thread-1] activated

DEBUG: [Thread-1] get blocked

DEBUG: [Thread-5] möchte 448 vom Konto konto mit Kontostand -417 auszahlen.

DEBUG: [Thread-5] get blocked

DEBUG: [Thread-6] möchte 122 auf das Konto konto mit Kontostand -417 einzahlen.

DEBUG: [Thread-6] hat 122 auf das Konto konto mit Kontostand -295 eingezahlt.

DEBUG: [Thread-9] möchte 437 vom Konto konto mit Kontostand -295 auszahlen.

DEBUG: [Thread-9] get blocked

DEBUG: [Thread-7] möchte 717 auf das Konto konto mit Kontostand -295 einzahlen.

DEBUG: [Thread-7] hat 717 auf das Konto konto mit Kontostand 422 eingezahlt.

DEBUG: [Thread-9] activated

DEBUG: [Thread-9] hat 437 vom Konto konto mit Kontostand -15 ausgezahlt.

DEBUG: [Thread-5] activated

DEBUG: [Thread-5] hat 448 vom Konto konto mit Kontostand -463 ausgezahlt.

DEBUG: [Thread-1] activated

DEBUG: [Thread-1] get blocked

DEBUG: [Thread-3] activated

DEBUG: [Thread-3] get blocked

DEBUG: [Thread-8] möchte 514 auf das Konto konto mit Kontostand -463 einzahlen.

DEBUG: [Thread-8] hat 514 auf das Konto konto mit Kontostand 51 eingezahlt.

DEBUG: [Thread-3] activated

DEBUG: [Thread-3] hat 346 vom Konto konto mit Kontostand -295 ausgezahlt.

DEBUG: [Thread-1] activated

DEBUG: [Thread-1] get blocked

*

* 通过

* DEBUG: [Thread-1] activated

DEBUG: [Thread-1] get blocked

DEBUG: [Thread-3] activated

DEBUG: [Thread-3] get blocked

...

DEBUG: [Thread-3] activated

DEBUG: [Thread-3] hat 346 vom Konto konto mit Kontostand -295 ausgezahlt.

DEBUG: [Thread-1] activated

DEBUG: [Thread-1] get blocked

* 这几行可以看出Java notifyALL通知到的线程结果貌似是随机的,并不完全固定

* */

class Konto {

// Kontonummer als String

public String kontonummer;

// Kontostand

public int kontostand;

// Konstruktor

Konto(String nummer, int einlage) {

this.kontonummer = nummer;

this.kontostand = einlage;

}

// getter-Methoden:

public synchronized int getKontostand() {

return this.kontostand;

}

public synchronized String getKontonummer() {

return this.kontonummer;

}

// Auszahlen

public synchronized void auszahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " auszahlen.");

while (getKontostand() < -100){

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] get blocked ");

try {wait();} catch (InterruptedException e) {return ;}

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] activated ");

}

kontostandvorher = getKontostand();

kontostand = kontostandvorher - betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " ausgezahlt.");

if (getKontostand() >= -100){

notifyAll();

}

if (getKontostand() < 1000){

notifyAll();

}

}

// Einzahlen

public synchronized void einzahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " einzahlen.");

while (getKontostand() >= 1000){

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] get blocked ");

try {wait();} catch (InterruptedException e){return ;}

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] activated ");

}

kontostandvorher = getKontostand();

this.kontostand = kontostandvorher + betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " eingezahlt.");

if (getKontostand() >= -100){

notifyAll();

}

if (getKontostand() <= 1000){

notifyAll();

}

}

}

d)实现一个交易类ZweikontenTransaktion,表示当从帐号A中取钱不够时,就尝试从B账户中取钱,单独都不够,那么试试看两个加起来够不够,如果也不够,那么就等待

答:

当一个线程能够调用比如帐号A.getKontostand()时,该线程获得A对象中的锁,但是调用完该方法后,锁就不一定还是由该线程所有,有可能会被其他线程获得,因此为了保证在一个线程操作时能不被别的线程抢走锁,要用 synchronized 锁住A和B

import java.util.ArrayList;

import java.util.Random;

import java.util.HashMap;

class Konto {

// Kontonummer als String

public String kontonummer;

// Kontostand

public int kontostand;

// Konstruktor

Konto(String nummer, int einlage) {

this.kontonummer = nummer;

this.kontostand = einlage;

}

// getter-Methoden:

public synchronized int getKontostand() {

return this.kontostand;

}

public synchronized String getKontonummer() {

return this.kontonummer;

}

// Auszahlen

public synchronized void auszahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " auszahlen.");

while (getKontostand() < -100){

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] get blocked ");

try {wait();} catch (InterruptedException e) {return ;}

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] activated ");

}

kontostandvorher = getKontostand();

kontostand = kontostandvorher - betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " vom Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " ausgezahlt.");

if (getKontostand() >= -100){

notifyAll();

}

if (getKontostand() < 1000){

notifyAll();

}

}

// Einzahlen

public synchronized void einzahlen(int betrag) {

int kontostandvorher = getKontostand();

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] möchte "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostandvorher

+ " einzahlen.");

while (getKontostand() >= 1000){

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] get blocked ");

try {wait();} catch (InterruptedException e){return ;}

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] activated ");

}

kontostandvorher = getKontostand();

this.kontostand = kontostandvorher + betrag;

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] hat "

+ betrag

+ " auf das Konto "

+ kontonummer

+ " mit Kontostand "

+ kontostand

+ " eingezahlt.");

if (getKontostand() >= -100){

notifyAll();

}

if (getKontostand() <= 1000){

notifyAll();

}

}

}

// Klasse für nebenläufig-ablaufende Transaktion

class Transaktion implements Runnable {

private Konto konto;

private int betrag;

private boolean istAuszahlung; // true = Auszahlung, false = Einzahlung

public Transaktion(Konto konto, int betrag, boolean auszahlung) {

this.konto = konto;

this.betrag = betrag;

this.istAuszahlung = auszahlung;

}

public void run() {

if (istAuszahlung) {

// Auszahlen

konto.auszahlen(betrag);

}

else {

// Einzahlen

konto.einzahlen(betrag);

}

}

}

class ZweiTransaktion implements Runnable {

private Konto kontoA, kontoB;

private int betrag;

private boolean istAuszahlung; // true = Auszahlung, false = Einzahlung

static int erfolgAuszahlen = 0;

public ZweiTransaktion(Konto kontoA, Konto kontoB, int betrag) {

this.kontoA = kontoA;

this.kontoB = kontoB;

this.betrag = betrag;

}

public void run() {

synchronized (kontoA){

synchronized (kontoB) {

if (kontoA.getKontostand() >= betrag) {

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] Konto A mit Kontostand " + kontoA.getKontostand());

kontoA.auszahlen(betrag);

int vorherErfolgAuszahlen = this.erfolgAuszahlen;

this.erfolgAuszahlen = vorherErfolgAuszahlen + betrag;

return;

}

if (kontoB.getKontostand() >= betrag) {

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] Konto B mit Kontostand " + kontoB.getKontostand());

kontoB.auszahlen(betrag);

int vorherErfolgAuszahlen = this.erfolgAuszahlen;

this.erfolgAuszahlen = vorherErfolgAuszahlen + betrag;

return;

}

while (kontoA.getKontostand() + kontoB.getKontostand() < betrag) {

try {

wait();

} catch (InterruptedException e) {

return;

}

}

if (kontoA.getKontostand() + kontoB.getKontostand() >= betrag) {

System.out.println("DEBUG: [" + Thread.currentThread().getName() + "] Konto A+B mit Kontostand " +

(kontoB.getKontostand() + kontoA.getKontostand()));

int vorherkontostandA = kontoA.getKontostand();

kontoA.auszahlen(vorherkontostandA);

kontoB.auszahlen(betrag - vorherkontostandA);

int vorherErfolgAuszahlen = this.erfolgAuszahlen;

this.erfolgAuszahlen = vorherErfolgAuszahlen + betrag;

}

if (kontoA.getKontostand() + kontoB.getKontostand() >= betrag) {

notify();

}

}

}

}

}

class KontoSimulationFuerAufgabeD {

public static void main(String[] args) {

Konto kontoA = new Konto("kontoA", 3*100);

Konto kontoB = new Konto("kontoB", 3*100);

Random rnd = new Random();

int checkExecution = kontoA.getKontostand();

checkExecution += kontoB.getKontostand();

ArrayList transaktionen = new ArrayList<>();

// Starte 10 Transaktionen

for (int i = 0; i < 10; ++i) {

int betrag = 100;

transaktionen.add(new Thread(new ZweiTransaktion(kontoA,kontoB,betrag)));

}

// Starte Threads

for (Thread t : transaktionen) {

t.start();

}

// Warte auf Beenden der Threads

for (Thread t : transaktionen) {

try {t.join();} catch (InterruptedException e) {}

}

System.out.println("Kontostand: " + (kontoA.getKontostand() + kontoB.getKontostand()));

}

}

e)完善下面这个转账类中的 run方法,实现能在不同帐号间(原子操作)转账。

public class KontoSimulation {

public static void main(String[] args) {

// Ein Konto mit initialem Kontostand 10

// Konto konto = new Konto("konto", 10);

// Random rnd = new Random();

//

// int checkExecution = konto.getKontostand();

// ArrayList transaktionen = new ArrayList<>();

// // Starte 10 Transaktionen

// for (int i = 0; i < 10; ++i) {

// int betrag = 1 + rnd.nextInt(100);

// boolean auszahlung = rnd.nextBoolean();

// transaktionen.add(new Thread(new Transaktion(konto,betrag,auszahlung)));

// checkExecution = checkExecution + (auszahlung?(-1)*betrag:betrag);

// }

// // Starte Threads

// for (Thread t : transaktionen) {

// t.start();

// // Auskommentieren für Sequentielle Simulation:

// // try {t.join();} catch (InterruptedException e) {} // 使程序不并行,join 会block调用它的线程

//

// }

// // Warte auf Beenden der Threads

// for (Thread t : transaktionen) {

// try {t.join();} catch (InterruptedException e) {}

// }

// // Prüfe Ergebnis:

// System.out.println("Kontostand erwartet: " + checkExecution);

// System.out.println("Tatsächlicher Kontostand: " + konto.getKontostand());

//

// Testprogramm fuer Aufgabenteil e):

KontoSimulationFuerAufgabeE.main(args);

}

}

// ============================

// Für Aufgabenteil e)

class Ueberweisung implements Runnable {

private volatile HashMap konten;

private int betrag;

private String von;

private String nach;

public Ueberweisung(HashMap konten, int betrag, String von, String nach) {

this.konten = konten;

this.betrag=betrag;

this.von=von;

this.nach=nach;

}

public void run() {

/**todo,下面就是已完成的**/

Konto firstLock, lastLock;

if (von.compareTo(nach) < 0){

firstLock = konten.get(von);

lastLock = konten.get(nach);

}

else{

firstLock = konten.get(nach);

lastLock = konten.get(von);

}

synchronized(firstLock){

synchronized (lastLock) {

Konto vonKonto = konten.get(von);

Konto nachKonto = konten.get(nach);

vonKonto.auszahlen(betrag);

nachKonto.einzahlen(betrag);

return;

}

}

}

}

// ==================================================

class KontoSimulationFuerAufgabeE {

public static void main(String[] args) {

HashMap konten= new HashMap<>();

for(int i=0; i<10; i++) {

konten.put("konto_" + i,new Konto("konto_" +i, 100));

}

Random rnd = new Random();

System.out.println("Tests fuer Aufgabenteil e)");

int numkonten=2;

System.out.println("Test 1: 2 Konten");

ArrayList transaktionen = new ArrayList<>();

// Starte 10 Ueberweisungen

for (int i = 0; i < 10; ++i) {

int betrag = 1 + rnd.nextInt(100);

int vonInt = rnd.nextInt(numkonten);

int nachInt = vonInt;

while (nachInt == vonInt) {

nachInt = rnd.nextInt(numkonten);

}

String von = "konto_" + vonInt;

String nach = "konto_" + nachInt;

transaktionen.add(new Thread(new Ueberweisung(konten,betrag,von,nach)));

}

// Starte Threads

for (Thread t : transaktionen) {

t.start();

}

// Warte auf Beenden der Threads

for (Thread t : transaktionen) {

try {t.join();} catch (InterruptedException e) {}

}

System.out.println("Test 2: Mehr Konten");

numkonten=10;

transaktionen = new ArrayList<>();

// Starte 10 Ueberweisungen

for (int i = 0; i < 10; ++i) {

int betrag = 1 + rnd.nextInt(100);

int vonInt = rnd.nextInt(numkonten);

int nachInt = vonInt;

while (nachInt == vonInt) {

nachInt = rnd.nextInt(numkonten);

}

String von = "konto_" + vonInt;

String nach = "konto_" + nachInt;

transaktionen.add(new Thread(new Ueberweisung(konten,betrag,von,nach)));

}

// Starte Threads

for (Thread t : transaktionen) {

t.start();

}

// Warte auf Beenden der Threads

for (Thread t : transaktionen) {

try {t.join();} catch (InterruptedException e) {}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值