Reputation: 33
I've got task like this
Build class StringTask, simulating long-term calculations, here consisting of the concatenation of strings.
The class constructor receives as argument the string to duplicate, and the number indicating how many times the string is to be amplified.
Class must implement the Runnable interface, and in its run() method is performed duplicating of a string, it should be done using + used to string variables (it is long-term operation). Usage of the + is a mandatory condition.
The object of class StringTask is treated as a task that can be performed in parallel with each other.
The status tasks are:
Define the following methods in class StringTask:
public String getResult ()
- returns the result of the
concatenationpublic TaskState getState ()
- returns the status of the taskpublic void start ()
- running the task in a separate thread
public void abort ()
- suspends the execution of a task code and operation of the thread
public boolean isDone ()
- returns true if the task is completed
normally or by interruption, false otherwise
The following program code:
public class Main {
public static void main(String[] args) throws InterruptedException {
StringTask task = new StringTask("A", 70000);
System.out.println("Task " + task.getState());
task.start();
if (args.length > 0 && args[0].equals("abort")) {
/*
<- here add the code interrupting the task after a second
and run it in a separate thread
*/
}
while (!task.isDone()) {
Thread.sleep(500);
switch(task.getState()) {
case RUNNING: System.out.print("R."); break;
case ABORTED: System.out.println(" ... aborted."); break;
case READY: System.out.println(" ... ready."); break;
default: System.out.println("uknown state");
}
}
System.out.println("Task " + task.getState());
System.out.println(task.getResult().length());
}
}
run without an argument should put something like this:
Task CREATED R.R.R.R.R.R.R.R.R. ... ready. Task READY 70000 and run with argument abort put something like this:
Task CREATED R. ... aborted. Task ABORTED 31700 Note 1. Main.java file can be modified only in the place marked /* <- */ Note 2. Do not use the method System.exit(...)
And got this solution
package zad2;
/**
* Created by szhyhalo on 09.04.17.
*/
public class StringTask implements Runnable {
public enum TaskState {
CREATED, RUNNING, ABORTED, READY
}
public boolean isDone = false;
public TaskState myState;
public String text;
public String resultText;
public Thread myThread;
public int operations;
public StringTask() {
myState = TaskState.CREATED;
}
public StringTask(String a, int i) {
this();
text = a;
operations = i;
resultText = "";
}
public boolean isDone() {
if (myState == TaskState.READY || myState == TaskState.ABORTED) return true;
return false;
}
public void abort() {
while (operations != 0) {
resultText += text;
operations--;
}
}
@Override
public void run() {
while (operations != 0) {
resultText += text;
operations--;
}
myState = TaskState.READY;
}
public TaskState getState() {
return myState;
}
public String getResult() {
return resultText;
}
public void start() {
myThread = new Thread(this);
myState = TaskState.RUNNING;
myThread.start();
}
}
But after testing, the system give me these errors, and i dont know hove to solve them.
Behaviour tests results - scoring decrease = -7
WHEN: We are invoking StringTask constructor with arguments 'Y' i 80000, and then we are staring the task
scoring decrease = -7
Requirements tests results - scoring decrease = -2
Case 1: scoring decrease = -1 - Some variables should have have volatile modifier
Case 2: scoring decrease = -1 - You should have check interrupted flag by interrupted lub isInterrupted method
How to solve this? I tried, but I have no idea.
Upvotes: 2
Views: 609
Reputation: 7166
Since neither of us knows the actual failing Behaviour tests, all we can do is guessing.
First thing first, in StringTask
you should use private volatile
variables. They should be private
for the sake of encapsulation. They should be volatile
so the multi-threaded changes will be visible. See this SO Q&A for further discussion about volatile.
Regarding the operations
counter, you better use AtomicInteger
because that supports multithreaded decrement and increment operations.
So these are the refined fields:
private volatile TaskState myState;
private volatile String text;
private volatile String resultText;
private final AtomicInteger operations = new AtomicInteger(0);
This requires a small change in the second constructor:
public StringTask(String a, int i) {
this();
text = a;
operations.set(i); // this is the change
resultText = "";
}
Also, the abort()
method needs to stop the execution in run()
. I'd do it like, abort()
updates the myState
flag, and run()
keeps reading that flag:
public void abort() {
myState = TaskState.ABORTED;
}
@Override
public void run() {
myState = TaskState.RUNNING;
while (operations.get() != 0 && myState != TaskState.ABORTED) {
resultText += text;
operations.decrementAndGet();
}
if (myState != TaskState.ABORTED) {
myState = TaskState.READY;
}
}
Note that these methods above use the get()
and the decrementAndGet()
method of AtomicInteger()
. This is a slight inconvenience we must pay for the very safe decrement / increment operations.
Upvotes: 1