Attempt 1
This commit is contained in:
parent
b63be079f7
commit
b9cf360b29
@ -36,10 +36,14 @@ public class BankSimulator {
|
||||
}
|
||||
|
||||
public void transferTo(BankAccount b, int amount) {
|
||||
synchronized (this.acc > b.acc ? this : b) {
|
||||
synchronized (this.acc > b.acc ? b : this) {
|
||||
balance -= amount;
|
||||
b.balance += amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Random r = new Random();
|
||||
|
||||
|
@ -22,6 +22,7 @@ public class QueueTest {
|
||||
private int sent = 0;
|
||||
|
||||
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) {
|
||||
q.put("" + i);
|
||||
sent++;
|
||||
@ -65,15 +66,18 @@ public class QueueTest {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
// Start the requested number of consumer threads
|
||||
for (Consumer c : consumers) {
|
||||
c.start();
|
||||
}
|
||||
|
||||
// Start the requested number of producer threads
|
||||
for (Producer p : producers) {
|
||||
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) {
|
||||
try {
|
||||
p.join();
|
||||
@ -83,6 +87,7 @@ public class QueueTest {
|
||||
}
|
||||
q.put("EOF");
|
||||
// terminate join at 10 secs since EOF marker may get lost
|
||||
// perform the same waiting for each consumer
|
||||
for (Consumer c : consumers) {
|
||||
try {
|
||||
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;
|
||||
for (Consumer consumer : consumers) {
|
||||
recv += consumer.numberConsumed();
|
||||
@ -109,10 +115,10 @@ public class QueueTest {
|
||||
new QueueTest(new UnsafeMessageQueue<String>(), 1, 3).run();
|
||||
new QueueTest(new UnsafeMessageQueue<String>(), 3, 3).run();
|
||||
|
||||
// System.out.println("** SAFE ** ");
|
||||
// new QueueTest(new SafeMessageQueue<String>(), 1, 1).run();
|
||||
// new QueueTest(new SafeMessageQueue<String>(), 3, 1).run();
|
||||
// new QueueTest(new SafeMessageQueue<String>(), 1, 3).run();
|
||||
// new QueueTest(new SafeMessageQueue<String>(), 3, 3).run();
|
||||
System.out.println("** SAFE ** ");
|
||||
new QueueTest(new SafeMessageQueue<String>(), 1, 1).run();
|
||||
new QueueTest(new SafeMessageQueue<String>(), 3, 1).run();
|
||||
new QueueTest(new SafeMessageQueue<String>(), 1, 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;
|
||||
|
||||
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> last = null;
|
||||
|
||||
@ -34,6 +24,13 @@ public class UnsafeMessageQueue<T> implements MessageQueue<T> {
|
||||
// TODO: given a new "val", create a new Link<T>
|
||||
// element to contain it and update "first" and
|
||||
// "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() {
|
||||
@ -44,10 +41,44 @@ public class UnsafeMessageQueue<T> implements MessageQueue<T> {
|
||||
// Ignored exception
|
||||
// TODO: what causes this exception to be thrown? and what should
|
||||
// you do with it ideally?
|
||||
}
|
||||
}
|
||||
// TODO: retrieve "val" from "first", update "first" to refer
|
||||
// to next element in list (if any). Return "val"
|
||||
/*
|
||||
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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user