List of Thread and accessing another list - java

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))

Related

Vector throws ConcurrentModificationException despite being synchronized

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.

Lclassname.classname; cannot be cast to classname.classname

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!

How to check for particular threshold for each URL?

I am working on an application in which I have list of machines and for each machine I need to hit the URL which will give me response back in XML and I need to parse the XML and extract one field (dataKey is the field name) value from it for each server and then check whether that field value is matching my threshold value or not. If it is matching my threshold value three times continuously then add that server in my another List.
So if machineA dataKey field is matching my threshold value continuously for three times, then add machineA to my list and if my machineB dataKey field value is also matching my same thresold value continuously for three times, then add machineB to the same list.
And after adding the machines to the list, reset the counter and start it again.
Below is my MachineStats class which holds each machine information -
public class MachineStats {
private String serverName;
private String serverURL;
private int dataKey = 0;
public MachineStats(String serverName, String serverURL) {
this.serverName = serverName;
this.serverURL = serverURL;
}
// getters here
public boolean isEligibleForEmail(Integer dataKeyCount, int thresholdLimit) {
try {
if (!TestUtils.isEmpty(dataKeyCount)) {
if (dataKeyCount >= thresholdLimit) {
dataKey++;
} else {
dataKey = 0;
}
if (dataKey > 3) {
dataKey = 0;
return true;
}
return false;
} else {
return false;
}
} catch (NumberFormatException ex) {
// log an exception
return false;
}
}
}
And below is the code I have in my main method which is the starting point where serverList holds list of machines.
// this holds machineA and machineB information
private static List<MachineStats> serverList = new LinkedList<MachineStats>();
while(true) {
ServerMetricsTask task = new ServerMetricsTask(serverList, thresholdLimit);
task.run();
TimeUnit.MINUTES.sleep(2); // sleep for 2 minutes
}
And below is my ServerMetricsTask class -
public class ServerMetricsTask {
private List<MachineStats> listOfServers;
private int thresholdLimit;
public ServerMetricsTask(List<MachineStats> listOfServers, int thresholdLimit) {
this.listOfServers = listOfServers;
this.thresholdLimit = thresholdLimit;
}
public void run() {
try {
List<String> holder = new LinkedList<String>();
for (MachineStats stats : listOfServers) {
Integer dataKeyCount = TestUtils.extractKey(stats.getServerName(), stats.getServerURL());
if (stats.isEligibleForEmail(dataKeyCount, thresholdLimit)) {
holder.add(stats.getServerName());
}
}
if (!holder.isEmpty()) {
// send an email with the machine name which has met the threshold
}
} catch (Exception ex) {
// log an exception
}
}
}
Problem Statement:-
Now I have above code working fine. As of now I am only checking for one property which is dataKey for each server. Now I need to do the same thing for two fields for each server. One field is dataKey and second field is customerKey and these two fields will be present in the XML response for each server.
So I have a fieldHolder map which holds my field name for which I need to check.
Here fieldHolder map holds -
key - field which we want to extract from the response coming from the URL.
value - is the threshold for that field which is a key.
Now I have modified my code like this -
// this holds machineA and machineB information
private static List<MachineStats> serverList = new LinkedList<MachineStats>();
private static Map<String, String> fieldHolder;
while(true) {
ServerMetricsTask task = new ServerMetricsTask(serverList, fieldHolder);
task.run();
TimeUnit.MINUTES.sleep(2); // sleep for 2 minutes
}
And below is my ServerMetricsTask class -
public class ServerMetricsTask {
private List<MachineStats> listOfServers;
private int thresholdLimit;
public ServerMetricsTask(List<MachineStats> listOfServers, Map<String, String> fieldHolder) {
this.listOfServers = listOfServers;
this.fieldHolder = fieldHolder;
}
public void run() {
try {
List<String> holder = new LinkedList<String>();
for (MachineStats stats : listOfServers) {
//now what should I do here?
// I guess I need to iterate fieldHolder map
}
if (!holder.isEmpty()) {
// send an email with the machine name which has met the threshold
}
} catch (Exception ex) {
// log an exception
}
}
}
The only problem I am facing is I don't how should I add logic so that it can extract two fields value by executing the URL after iterating fieldHolder map and then also check the whether those two field or either of them is meeting the threshold limit three times continuously. And if they are meeting the threshold limit three times continuously then add that machine name to the list holder.
I already know how to extract those fields values given an URL by parsing XML response.
first, change dataKey in MachineStats to keyMap
public class MachineStats {
...
private HashMap<String,int> keyMap = new HashMap<String,int>;
...
public HashMap<String,int> getKeyMap() {
return this.keyMap;
}
}
each time you create a new MachineStats, populate its keyMap with keys needed.
keyMap.put("Key1", 0);
keyMap.put("Key2", 0);
// etc. I don't know how you will do it
Now, you need to change TestUtils.extractKey() so it will accept and extract any arbitrary key name. Contrary to what I said in my comments, it's better not to change its inner logic so we won't make any more changes there.
TestUtils.extractKey(String keyName, String serverName, string serverURL);
Now, ServerMetricsTask iterates the machine list, and also iterates the machine's keymap:
public class ServerMetricsTask {
...
for (MachineStats stats : listOfServers) {
//now what should I do here?
// I guess I need to iterate fieldHolder map
HashMap<String, int> keymap = stats.getKeyMap();
int key_count = keymap.size();
int valid_count = 0;
Set<String> keys = keymap.keySet();
for (String key : keys) {
int count = keymap.get(key);
int result = TestUtils.extractKey(key, stats.getServerName(), stats.getServerURL());
if (stats.isEligibleForEmail(result, thresholdLimit)) {
count++;
} else {
// here you can do count = 0 if you need strictly continuous appearance of the key
}
keymap.put(key, count);
if (count >= 3) valid_count++;
}
// now decide if you need all keys to be valid or just some
if (valid_count == key_count) holder.add(stats.getServerName());
...

Java boolean array with one element

So I've come accross this bit of code while scavaging through org.eclipse.ui.internal.Workbench:
final boolean[] initOK = new boolean[1];
if (getSplash() != null) {
final boolean[] initDone = new boolean[] { false };
final Throwable[] error = new Throwable[1];
Thread initThread = new Thread() {
/*
* (non-Javadoc)
*
* #see java.lang.Thread#run()
*/
public void run() {
try {
// declare us to be a startup thread so that our
// syncs will be executed
UISynchronizer.startupThread.set(Boolean.TRUE);
initOK[0] = Workbench.this.init();
} catch (Throwable e) {
error[0] = e;
} finally {
initDone[0] = true;
display.wake();
}
}
};
initThread.start();
..............
}
What's the purpose of creating arrays with just one element? Is it faster? I'm definitly missing something here.
The advantage of using this approach is that the arrays cannot be modified (because they are final), however, their content can be changed.
A useful example is that you can use these arrays and modify their first entry in anonymous inner classes without having to make them (static) fields.
As stated in the comments above, another use-case is that this array can be used to pass it to a method expecting an array type.

Reach an variable array from action button clicked java

I am stucked by coding and I need your help.
Ok first of all I have an array variable under a class.
I get the values from excel and put inside the nodename array like as follows.I shortened the following codes.
Following class Readexcel is also under ConfigGenerator Class.
class ReadExcel {
private String inputFile;
public void setInputFile(String inputFile) {
this.inputFile = inputFile;
}
public void read() throws IOException {
File inputWorkbook = new File(inputFile);
Workbook nodes;
try {
nodes = Workbook.getWorkbook(inputWorkbook);
// Get the first sheet
Sheet nodessheet = nodes.getSheet(1);
String[] nodename = new String[nodessheet.getRows()];
for (int i = 1; i < nodessheet.getRows(); i++) {
int j = 0;
Cell x1a = nodessheet.getCell(0, i);
nodename[j] = x1a.getContents();
j++;
// System.out.println(nodename[j]);
}
} catch (BiffException e) {
// e.printStackTrace();
}
}
}
But my problem is to reaching this variable from a button action.
public class ConfigGenerator extends javax.swing.JFrame {
public ConfigGenerator() {
initComponents();
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
}
private void generateActionPerformed(java.awt.event.ActionEvent evt) {
try {
Writer output = null;
for (String name: Generator.ConfigGenerator.ReadExcel.nodename[????]){
System.out.println(name);
}
output.close();
System.out.println("Your files has been written.");
} catch (IOException ex) {
Logger.getLogger(ConfigGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
The parts that i added question mark is my problem for the last 2 days I am tring but couldn't get the values from that array.
First I need to get lenght of array and second the values :)
Thank you very much for your help in advance.
Ok I edited the question by adding the whole section with codes.
Maybe you mean that you want to get the array lenght using nodename.length, but I have two issues with your code:
First you access nodename as an array local to your action, then later access it as a static variable of class ConfigGenerator, which means you are accessing two different arrays.
Also, you access the nodename array as a static variable (although even the .class is not necessary), but you mentioned it as a "array variable" which means you need first to create a new instance of class ConfigGenerator, initializing the array nodename, and then you can use it in other classes.
First of all, the way to retrieve the length of an array in Java is
nodename.length
not
nodename.getlength()
But you could also use the shortened syntax to loop through all elements in the specific array:
for (Object obj : array) {
System.out.println(obj);
}
In your case it would be:
for (Object obj : ConfigGenerator.nodename) { //replace Object with your datatype
System.out.println(obj);
}

Categories

Resources