Attempt 1
This commit is contained in:
parent
b63be079f7
commit
b9cf360b29
@ -36,8 +36,12 @@ public class BankSimulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void transferTo(BankAccount b, int amount) {
|
public void transferTo(BankAccount b, int amount) {
|
||||||
balance -= amount;
|
synchronized (this.acc > b.acc ? this : b) {
|
||||||
b.balance += amount;
|
synchronized (this.acc > b.acc ? b : this) {
|
||||||
|
balance -= amount;
|
||||||
|
b.balance += amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ public class QueueTest {
|
|||||||
private int sent = 0;
|
private int sent = 0;
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Adds 50000 messages to the queue, each containing the string representation of the numbers counting up
|
||||||
for (int i = 0; i < 50000; ++i) {
|
for (int i = 0; i < 50000; ++i) {
|
||||||
q.put("" + i);
|
q.put("" + i);
|
||||||
sent++;
|
sent++;
|
||||||
@ -65,15 +66,18 @@ public class QueueTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Start the requested number of consumer threads
|
||||||
for (Consumer c : consumers) {
|
for (Consumer c : consumers) {
|
||||||
c.start();
|
c.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the requested number of producer threads
|
||||||
for (Producer p : producers) {
|
for (Producer p : producers) {
|
||||||
p.start();
|
p.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Join each producer thread - this awaits completion of each thread by joining this thread to its execution
|
||||||
|
// This loops awaits the completion of all producers
|
||||||
for (Producer p : producers) {
|
for (Producer p : producers) {
|
||||||
try {
|
try {
|
||||||
p.join();
|
p.join();
|
||||||
@ -83,6 +87,7 @@ public class QueueTest {
|
|||||||
}
|
}
|
||||||
q.put("EOF");
|
q.put("EOF");
|
||||||
// terminate join at 10 secs since EOF marker may get lost
|
// terminate join at 10 secs since EOF marker may get lost
|
||||||
|
// perform the same waiting for each consumer
|
||||||
for (Consumer c : consumers) {
|
for (Consumer c : consumers) {
|
||||||
try {
|
try {
|
||||||
c.join(10000);
|
c.join(10000);
|
||||||
@ -91,6 +96,7 @@ public class QueueTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare the total number of messages received to the total number sent
|
||||||
int recv = 0;
|
int recv = 0;
|
||||||
for (Consumer consumer : consumers) {
|
for (Consumer consumer : consumers) {
|
||||||
recv += consumer.numberConsumed();
|
recv += consumer.numberConsumed();
|
||||||
@ -109,10 +115,10 @@ public class QueueTest {
|
|||||||
new QueueTest(new UnsafeMessageQueue<String>(), 1, 3).run();
|
new QueueTest(new UnsafeMessageQueue<String>(), 1, 3).run();
|
||||||
new QueueTest(new UnsafeMessageQueue<String>(), 3, 3).run();
|
new QueueTest(new UnsafeMessageQueue<String>(), 3, 3).run();
|
||||||
|
|
||||||
// System.out.println("** SAFE ** ");
|
System.out.println("** SAFE ** ");
|
||||||
// new QueueTest(new SafeMessageQueue<String>(), 1, 1).run();
|
new QueueTest(new SafeMessageQueue<String>(), 1, 1).run();
|
||||||
// new QueueTest(new SafeMessageQueue<String>(), 3, 1).run();
|
new QueueTest(new SafeMessageQueue<String>(), 3, 1).run();
|
||||||
// new QueueTest(new SafeMessageQueue<String>(), 1, 3).run();
|
new QueueTest(new SafeMessageQueue<String>(), 1, 3).run();
|
||||||
// new QueueTest(new SafeMessageQueue<String>(), 3, 3).run();
|
new QueueTest(new SafeMessageQueue<String>(), 3, 3).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
83
src/uk/ac/cam/jsh77/fjava/tick3/SafeMessageQueue.java
Normal file
83
src/uk/ac/cam/jsh77/fjava/tick3/SafeMessageQueue.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 Andrew Rice <acr31@cam.ac.uk>, Alastair Beresford <arb33@cam.ac.uk>, J.S. Hillion
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package uk.ac.cam.jsh77.fjava.tick3;
|
||||||
|
|
||||||
|
public class SafeMessageQueue<T> implements MessageQueue<T> {
|
||||||
|
private Link<T> first = null;
|
||||||
|
private Link<T> last = null;
|
||||||
|
|
||||||
|
public synchronized void put(T val) {
|
||||||
|
Link<T> link = new Link<>(val);
|
||||||
|
if (first == null && last == null) {
|
||||||
|
first = last = link;
|
||||||
|
} else {
|
||||||
|
last.next = link;
|
||||||
|
last = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized T take() {
|
||||||
|
while (first == null) { // use a loop to block thread until data is available
|
||||||
|
try {
|
||||||
|
this.wait();
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
// QUESTION: what causes this exception to be thrown? and what should
|
||||||
|
// you do with it ideally?
|
||||||
|
|
||||||
|
/*
|
||||||
|
The exception is thrown when the thread is interrupted while blocking (sleeping here).
|
||||||
|
To correctly support interrupts, the Thread should exit cleanly. In this case, the best way to do that
|
||||||
|
is to return null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Link<T> oldFirst = first;
|
||||||
|
if (last == oldFirst) last = null;
|
||||||
|
first = oldFirst.next;
|
||||||
|
return oldFirst.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UnsafeMessageQueue{" +
|
||||||
|
"first=" + first +
|
||||||
|
", last=" + last +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Link<L> {
|
||||||
|
L val;
|
||||||
|
Link<L> next;
|
||||||
|
|
||||||
|
Link(L val) {
|
||||||
|
this.val = val;
|
||||||
|
this.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Link{" +
|
||||||
|
"val=" + val +
|
||||||
|
", next=" + next +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,16 +17,6 @@
|
|||||||
package uk.ac.cam.jsh77.fjava.tick3;
|
package uk.ac.cam.jsh77.fjava.tick3;
|
||||||
|
|
||||||
public class UnsafeMessageQueue<T> implements MessageQueue<T> {
|
public class UnsafeMessageQueue<T> implements MessageQueue<T> {
|
||||||
private static class Link<L> {
|
|
||||||
L val;
|
|
||||||
Link<L> next;
|
|
||||||
|
|
||||||
Link(L val) {
|
|
||||||
this.val = val;
|
|
||||||
this.next = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Link<T> first = null;
|
private Link<T> first = null;
|
||||||
private Link<T> last = null;
|
private Link<T> last = null;
|
||||||
|
|
||||||
@ -34,6 +24,13 @@ public class UnsafeMessageQueue<T> implements MessageQueue<T> {
|
|||||||
// TODO: given a new "val", create a new Link<T>
|
// TODO: given a new "val", create a new Link<T>
|
||||||
// element to contain it and update "first" and
|
// element to contain it and update "first" and
|
||||||
// "last" as appropriate
|
// "last" as appropriate
|
||||||
|
Link<T> link = new Link<>(val);
|
||||||
|
if (first == null && last == null) {
|
||||||
|
first = last = link;
|
||||||
|
} else {
|
||||||
|
last.next = link;
|
||||||
|
last = link;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T take() {
|
public T take() {
|
||||||
@ -44,10 +41,44 @@ public class UnsafeMessageQueue<T> implements MessageQueue<T> {
|
|||||||
// Ignored exception
|
// Ignored exception
|
||||||
// TODO: what causes this exception to be thrown? and what should
|
// TODO: what causes this exception to be thrown? and what should
|
||||||
// you do with it ideally?
|
// you do with it ideally?
|
||||||
|
/*
|
||||||
|
The exception is thrown when the thread is interrupted while blocking (sleeping here).
|
||||||
|
To correctly support interrupts, the Thread should exit cleanly. In this case, the best way to do that
|
||||||
|
is to return null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: retrieve "val" from "first", update "first" to refer
|
|
||||||
// to next element in list (if any). Return "val"
|
Link<T> oldFirst = first;
|
||||||
return null;
|
if (last == oldFirst) last = null;
|
||||||
|
first = oldFirst.next;
|
||||||
|
return oldFirst.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UnsafeMessageQueue{" +
|
||||||
|
"first=" + first +
|
||||||
|
", last=" + last +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Link<L> {
|
||||||
|
L val;
|
||||||
|
Link<L> next;
|
||||||
|
|
||||||
|
Link(L val) {
|
||||||
|
this.val = val;
|
||||||
|
this.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Link{" +
|
||||||
|
"val=" + val +
|
||||||
|
", next=" + next +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user