I had an ArrayList that was being operated on by multiple threads, which wasn't working as the ArrayList isn't synchronized. I switched the list to a Vector as instructed by my professor. Vector is synchronized, but I'm having exceptions thrown related to synchronization.
Why is this happening, and how can I avoid concurrency exceptions in my code? I don't want to just play around until something works, I want to do the best thing. Thanks!
Exception:
Exception in thread "Thread-3" java.util.ConcurrentModificationException
at java.util.Vector$Itr.checkForComodification(Vector.java:1184)
at java.util.Vector$Itr.next(Vector.java:1137)
at BytePe4D$ReadInts.run(BytePe4D.java:64)
Code:
import java.io.*;
import java.util.Vector;
public class BytePe4D {
private Vector<Integer> numbers;
public static void main(String[] args) {
new BytePe4D();
}
public BytePe4D() {
// Create ArrayList and reset sum
numbers = new Vector<Integer>();
// Call addInts 8 times, with filenames integer1.dat through integer8.dat
for (int i = 1; i <= 8; i++) {
File file = new File("PE Data/integer" + i + ".dat");
ReadInts thread = new ReadInts(file);
thread.start();
}
}
/** Represents a Thread instance */
class ReadInts extends Thread {
File file;
public ReadInts(File _file) {
file = _file;
}
#Override
public void run() {
int count = 0; // track number of records read
int sum = 0;
try {
// Open stream to binary data file integer1.dat
FileInputStream in = new FileInputStream(file);
// Buffer the stream
BufferedInputStream bin = new BufferedInputStream(in);
// Access the primitive data
DataInputStream din = new DataInputStream(bin);
try {
// Read file until end reached
while (true) {
numbers.add(din.readInt());
count++;
}
} catch (EOFException eof) {
// System.out.println("End of file reached.");
} finally {
// Close streams
din.close();
}
} catch (FileNotFoundException fnf) {
System.out.println("File does not exist: " + file.getName());
return;
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Calculate sum of numbers read
for (int num : numbers) {
sum += num;
}
// Write info
System.out.println(
String.format("%s%s%-5s%s%-8d%-5s%s%-12d%-5s%s%d",
"Filename = ", file.getName(), "",
"Count = ", count, "",
"Sum = ", sum, "",
"In List = ", numbers.size()));
}
}
}
From the docs:
if the vector is structurally modified at any time after the iterator
is created, in any way except through the iterator's own remove or add
methods, the iterator will throw a ConcurrentModificationException.
The following code creates an iterator under the covers:
for (int num : numbers) {
sum += num;
}
So when one threads modifies the vector (by adding elements) while another vector is iterating it - you'll see a ConcurrentModificationException
There are different options to solve it, one way could be to read from a file into another vector and when the reading is done assign this other vector to numbers (since assignment is an atomic operation). Keep in mind that in order for the change to be visible to other threads you'll need to declare numbers as volatile.
Your code seems wrong.
I don't see why you need a shared vector, if each thread is to calculate the sum of records from an individual file. On the other hand, if you want to calculate the sum of records from all files, you should do it after every thread has completed.
Depending on which you want, you can either 1) create a vector for each thread and calculate the sum for each file or, 2) in the main thread, wait for all threads to complete then calculate the sum for all files.
Related
I am getting an InputStream that contains multiple elements, they are scanned, parsed, iterated by a Stream in a serial way (same order they had in the InputStream), and then persisted in a DB. This works fine.
Now, I am trying to iterate the Stream in parallel way, with Stream<T>.parallel(), so while one thread is blocked persisting, other ones can still scanning the InputStream and persisting.
Then, I tried to parallelized the resulting Stream<MyElement> with Stream<T>.parallel(). To check that the parallelization works, I added into the stream a map function that add a random delay. I was expecting that the resulted elements were printed in a random order.
But the result is not the expected one. The elements are still shown in the file order.
Is there a way to properly iterate this stream in parallel?
public class FromInputStreamToParallelStream {
public static Stream<MyElement> getStream(InputStream is) {
try (var scanner = new Scanner(is)) {
return scanner//
.useDelimiter("DELIMITER")
.tokens()
.parallel()
.map(MyElementParser::parse);
}
}
#Test
public void test() throws IOException {
try (InputStream in = Files.newInputStream(Paths.get("my-file.xml"));) {
getStream(in)
.map(FromInputStreamToParallelStream::sleepRandom)
.forEach(System.out::println);
}
}
private static MyElement sleepRandom(MyElement element) {
var randomNumber = new Random().nextInt(10);
System.out.println("wait. " + randomNumber);
try {
TimeUnit.SECONDS.sleep(randomNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return element;
}
}
I guess I gonna need to implement my own Spliterator<T>.
Thanks in advance.
i'm writing a program for a game called 'Trivia'. Below is the source code:
Trivia.java
public class Trivia implements Serializable {
private String question;
private String answer;
private int points;
public Trivia() {
question = " ";
answer = " ";
points = 0;
}
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
public int getPoints() {
return points;
}
public void setQuestion(String q) {
question = q;
}
public void setAnswer(String a) {
answer = a;
}
public void setPoints(int p) {
points = p;
}
}
Driver.java
public class Driver {
public static void main(String[] args) {
Trivia[] t = new Trivia[5];
for (int i = 0; i < 5; i++) {
t[i] = new Trivia();
}
t[0].setQuestion("How many states are in the US?");
t[0].setAnswer("50");
t[0].setPoints(1);
t[1].setQuestion("Who is the richest person in the US");
t[1].setAnswer("You");
t[1].setPoints(1);
t[2].setQuestion("How many senators come from each state?");
t[2].setAnswer("2");
t[2].setPoints(2);
t[3].setQuestion("What is the largest state?");
t[3].setAnswer("Alaska");
t[3].setPoints(2);
t[4].setQuestion("Who was the thrid president?");
t[4].setAnswer("Thomas Jefferson");
t[4].setPoints(3);
ObjectOutputStream outputStream = null;
try {
outputStream = new ObjectOutputStream(new FileOutputStream("C:\\Work\\workspace\\aman\\src\\trivia\\trivia.dat"));
} catch (IOException e) {
System.out.println("Could not open file");
System.exit(0);
}
try {
outputStream.writeObject(t);
outputStream.close();
} catch (IOException e) {
System.out.println("Writing error");
System.exit(0);
}
ArrayList<Trivia> triviaQuestions = new ArrayList<Trivia>();
try {
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("C:\\Work\\workspace\\aman\\src\\trivia\\trivia.dat"));
for(int i=0; i<5; i++){ // Repeats the content of the loop five times
triviaQuestions.add((Trivia) inputStream.readObject());
}
inputStream.close(); // Closes the input stream because it is not longer needed
} catch (IOException | ClassNotFoundException e) {
System.out.println("File not found.");
System.exit(0);
}
Trivia yourRandomTrivia = triviaQuestions.get((new Random()).nextInt(triviaQuestions.size())); // This will be your random question
}
// You did not get an auto complete suggestion because you typed outside of a method
}
noe when I try to run this program, I get an error saying "Ltrivia.Trivia; cannot be cast to trivia.Trivia". The error is thrown in class Driver on line " triviaQuestions.add((Trivia) inputStream.readObject());". I did some research on this and found that 'L' means array of a datatype. But, I have simple created an arrayList of type Trivia and trying to add each element I get from the inputStream by casting them to Trivia class.
Does anybody have any suggestions on this?
Your code is writing an Array of Trivia objects.
Then you try to read and add that to a list of Trivia objects.
You cant add arrays of Trivia to an List of Trivia!
And that is what the message is telling you: you cant cast the type Trivia[] to Trivia. Because an array of X is not the same as a single X.
One solution: instead of writing t as a whole, you can simply iterate t and write the members of the array. Of course that means that you have to somehow remember how many elements you wrote into that stream. You could get there by first writing an Integer object representing the number of Trivia objects that will follow.
The other solution: just read back that Trivia[]; and iterate it then; to add the various Trivia objects one by one.
Edit: on your comment: when you read from an ObjectInputStream you get back those things that you put into your file/stream earlier on. As said: your code puts a single object of type ARRAY of Trivia into bytes ... and then you want to read that thing back as a single Trivia object! That does not work!
I am trying to write a method that will read a text file that looks like this:
N 1000.0 NY
R 2000.0 CA 0.09
R 500.0 GA 0.07
N 2000.0 WY
O 3000.0 Japan 0.11 20.0
N 555.50 CA
O 3300.0 Ecuador 0.03 30.0
R 600.0 NC 0.06
The starting letters are the different types of orders. Each type of order has different parameters. I want the method to read the orders from the text file in a format like this:
Type Price Location [TaxRate] [Tariff]. My point of confusion is how to sort the data into the array by type.
public static ArrayList<Order> readOrders (String fileName)
{
File file = new File (fileName);
scan = null;
try {
scan = new Scanner(file);
} catch (FileNotFoundException e) {
System.out.println("Error, file not found: " + file.toString());
e.printStackTrace();
}
Order[] order = new Order[8];
for (int i = 0; i < order.length; i++) {
String data = scan.nextLine(); // you need to use nextLine to read a whole line
String[] val = data.split(" ");
String type = val[0]; // Since its a String
double price = Double.parseDouble(val[1]);
String location = val[2]; // Since its a String
double taxRate = 0.0; // Default values
double tariff = 0.0; // Default values
try { // Incase they are not present - error handling
taxRate = Double.parseDouble(val[3]);
tariff = Double.parseDouble(val[4]);
} catch (ArrayIndexOutOfBoundsException e) {
}
ArrayList <Order> orders =new ArrayList<Order>(Arrays.asList(order));
return orders;
I cannot get it to work with my main method:
public static void main(String[] args)
{
ArrayList<Order> orders2 = readOrders("orders.txt");
for( Order o2 : orders2)
{
System.out.println( o2.printOrder("Long"));
}
for( Order o2 : orders2)
{
System.out.println(o2.printOrder("Short"));
}
}
This is my error code:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The method printOrder(String) is undefined for the type Order
The method printOrder(String) is undefined for the type Order
at prob1.OrderTester.main(OrderTester.java:19)
Well. it is a compilation error. The class Order doesn't include the method you are calling. E.g.
printOrder("Long")
Check the class Order. Here you have not provided it
Like already mentioned you got a compilation error. Your Order class need to have a printOrder(String) method.
You should also check your readOrders method.
It seems to always return empty Orders because you create the order array with
Order[] order = new Order[8];
But NEVER assign something with something like:
order[i] = new Order(type, price, location, etc ...);
The catch block seems also wrong
} catch (ArrayIndexOutOfBoundsException e) {
you need to close it!
The best practice for sorting an array list by type is:
If it's not already, make Order implement Comparable and override compareTo(Order o) to return the following, assuming there is a String type field and it has an accessor method getType():
#Override
public int compareTo(Order o) {
return type.compareTo(o.getType());
}
Then simply call Arrays.sort(orders) once you've scanned the file.
Or use a Comparator.
Having said that, here's a short list of some of the wrongest things in your code:
(1) You haven't posted the source for the Order class, which is the main class with regards to the question you've asked. Makes it hard to give a more specific answer.
(2) The readOrders() function you've posted either is incomplete or (even if you add the couple of missing curly braces, and close the for loop) returns a list containing 8 null references. You need to instantiate the Order objects.
(3) Why use an array Order[] instead of just using the list with ArrayList.add()?
(4) Any time the Scanner fails to load the file, it will throw a NullPointerException on the first line after the catch block.
(5) Checking if your array has ended by catching ArrayIndexOutOfBoundsException() is bad practice for a multitude of reasons. Google it if you don't believe me.
(6) You get a compilation error because the Order.printOrder(String) is not defined. Define it, or better yet override Order.toString().
Consider rewriting your code to address these issues. There's likely more, these are just the things that jump out at first glance.
I figured out the answer I was looking for. Here it is:
public static ArrayList<Order> readOrders (String fileName)
{
File file = new File (fileName);
ArrayList<Order> o = new ArrayList<Order>();
scan = null;
try {
scan = new Scanner(file);
} catch (FileNotFoundException e) {
System.out.println("Error, file not found: " + file.toString());
e.printStackTrace();
}
while (scan.hasNext())
{
String fl = scan.next();
if (fl.equals("N"))
{
NonProfitOrder n = new NonProfitOrder(scan.nextDouble(), scan.next());
o.add(n);
}
else if (fl.equals("R"))
{
RegularOrder r = new RegularOrder (scan.nextDouble(), scan.next(), scan.nextDouble());
o.add(r);
}
else
{
OverseasOrder oo = new OverseasOrder(scan.nextDouble(), scan.next(), scan.nextDouble(), scan.nextDouble());
o.add(oo);
}
}
return o;
}
I've already made another question close to this one several minutes ago, and there were good answers, but it was not what I was looking for, so I tried to be a bit clearer.
Let's say I have a list of Thread in a class :
class Network {
private List<Thread> tArray = new ArrayList<Thread>();
private List<ObjectInputStream> input = new ArrayList<ObjectInputStream>();
private void aMethod() {
for(int i = 0; i < 10; i++) {
Runnable r = new Runnable() {
public void run() {
try {
String received = (String) input.get(****).readObject(); // I don't know what to put here instead of the ****
showReceived(received); // random method in Network class
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
tArray.add(new Thread(r));
tArray.get(i).start();
}
}
}
What should I put instead of ** ?
The first thread of the tArray list must only access the first input of the input list for example.
EDIT : Let's assume my input list has already 10 elements
It would work if you put i. You also need to add an ObjectInputStream to the list for each thread. I recommend you use input.add for that purpose. You also need to fill the tArray list with some threads, use add again there.
Here's the solution:
private void aMethod() {
for(int i = 0; i < 10; i++) {
final int index = i; // Captures the value of i in a final varialbe.
Runnable r = new Runnable() {
public void run() {
try {
String received = input.get(index).readObject().toString(); // Use te final variable to access the list.
showReceived(received); // random method in Network class
} catch (Exception exception) {
exception.printStackTrace();
}
}
};
tArray.add(new Thread(r));
tArray.get(i).start();
}
}
As you want each thread to access one element from the input array you can use the value of the i variable as an index into the list. The problem with using i directly is that an inner class cannot access non-final variables from the enclosing scope. To overcome this we assign i to a final variable index. Being final index is accessible by the code of your Runnable.
Additional fixes:
readObject().toString()
catch(Exception exception)
tArray.add(new Thread(r))
How can I make sure the print out order same as the order in the original array, when two threads are used? I want it printing '0 1 2 3 4 5 6 7 8 9', but currently the order is not guaranteed. Any way to make it in order? Thank you a lot.
public class Test {
public static void main(String[] args){
DataStore dataStore = new DataStore();
for(int i=0; i<10; i++){
dataStore.add(String.valueOf(i));
}
CopyThread t1 = new CopyThread(dataStore);
CopyThread t2 = new CopyThread(dataStore);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch(Throwable t) {
}
}
}
class CopyThread extends Thread {
private DataStore data;
public CopyThread(DataStore data){
this.data = data;
}
public void run(){
DataStore.Line line = null;
int lineID;
while( (line = data.getLine()) != null ){
lineID = line.id;
System.out.println(Thread.currentThread().getName() + ": " + lineID);
}
}
}
class DataStore {
ArrayList<String> lines = new ArrayList<String>();
int current = 0;
public synchronized Line getLine () {
if (current >= lines.size()) {
return null;
}
Line line = new Line(lines.get(current), current);
current++;
return line;
}
public synchronized void add (String s) {
lines.add(s);
}
public synchronized int size () {
return lines.size();
}
public static class Line {
public String line;
public int id;
public Line (String str, int i) {
line = str;
id = i;
}
}
}
Try Vector instead of ArrayList .
Vector
The Vector class implements a growable array of objects. Like an
array, it contains components that can be accessed using an integer
index. However, the size of a Vector can grow or shrink as needed to
accommodate adding and removing items after the Vector has been
created.
Each vector tries to optimize storage management by maintaining a
capacity and a capacityIncrement. The capacity is always at least as
large as the vector size; it is usually larger because as components
are added to the vector, the vector's storage increases in chunks the
size of capacityIncrement. An application can increase the capacity of
a vector before inserting a large number of components; this reduces
the amount of incremental reallocation.
The Iterators returned by Vector's iterator and listIterator methods
are fail-fast: if the Vector is structurally modified at any time
after the Iterator is created, in any way except through the
Iterator's own remove or add methods, the Iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the Iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future. The Enumerations returned by Vector's elements method
are not fail-fast.
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification. Fail-fast
iterators throw ConcurrentModificationException on a best-effort
basis. Therefore, it would be wrong to write a program that depended
on this exception for its correctness: the fail-fast behavior of
iterators should be used only to detect bugs.
You can use synchronize to achieve that:
synchronized(data) {
while( (line = data.getLine()) != null ){
lineID = line.id;
System.out.println(Thread.currentThread().getName() + ": " + lineID);
}
}