I have a simple loop over a String array which then passes the String to a threadlist method. However I can't seem to print out both String's. It just prints the second name "Fred" which makes me think that I am overwriting the first String with the second String. How can I make the ArrayList include both Strings "Tim" and "Fred"?
import java.util.ArrayList;
public class Threads extends Thread implements Runnable{
private ArrayList threadList;
private String e;
public static void main(String[] args) {
String[] elements = {"Tim","Fred"};
Threads t = new Threads();
for (String e: elements) {
t.threadL(e);
}
//loop over the elements of the String array and on each loop pass the String to threadL
for (int index = 0;index<t.threadList.size();index++){
System.out.print(t.threadList.get(index));
}
//loop over the threadList arraylist and printout
}
public ArrayList<String> threadL(String e) {
threadList = new ArrayList<>();
threadList.add(e);
return(threadList);
}
}
The direct solution to your problem is that you are instantiating the threadList variable each time the method threadL is invoked. So on the second call, whatever was stored before is disregarded and the new content is added:
public ArrayList<String> threadL(String e) {
threadList = new ArrayList<>(); // <-- instantiates a new list each time it is called
threadList.add(e);
return threadList;
}
You should instantiate that list only once, for example where it is declared. Also, you definitely should not use raw types like List but always the typed version:
private List<String> threadList = new ArrayList<>();
Note that in the given example, you are actually not using any Thread or Runnable feature (since you did not override run() or started the thread). Also, prefer implementing Runnable over extending Thread.
You are instantiating a new array list each time you go through loop. That's why you can't see element[0], since it's replaced with new list.
Related
I'm new to multithreading in general, so I still don't fully understand it. I don't get why my code is having issues. I'm trying to populate an ArrayList with the first 1000 numbers, and then sum all of them using three threads.
public class Tst extends Thread {
private static int sum = 0;
private final int MOD = 3;
private final int compare;
private static final int LIMIT = 1000;
private static ArrayList<Integer> list = new ArrayList<Integer>();
public Tst(int compare){
this.compare=compare;
}
public synchronized void populate() throws InterruptedException{
for(int i=0; i<=Tst.LIMIT; i++){
if (i%this.MOD == this.compare){
list.add(i);
}
}
}
public synchronized void sum() throws InterruptedException{
for (Integer ger : list){
if (ger%MOD == this.compare){
sum+=ger;
}
}
}
#Override
public void run(){
try {
populate();
sum();
System.out.println(sum);
} catch (InterruptedException ex) {
Logger.getLogger(Tst.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
Tst tst1 = new Tst(0);
tst1.start();
Tst tst2 = new Tst(1);
tst2.start();
Tst tst3 = new Tst(2);
tst3.start();
}
}
I expected it to print "500.500", but instead it prints this:
162241
328741
Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at tst.Tst.sum(Tst.java:38)
at tst.Tst.run(Tst.java:50)
BUILD SUCCESSFUL (total time: 2 seconds)
The problem is happening because your methods are synchronized in "object level", I mean, the monitor lock it uses is of a particular object (tst1,tst2,tst3). In other words, each synchronized method is using a different lock.
Change your synchronized methods to static as a first step to fix it.
while run of tst1 is counting the sum in for-each then run of tst2 might increasing the size of list. So its throwing concurrent modification exception. Using a join can help.
public static void main(String[] args) {
Tst tst1 = new Tst(0);
tst1.start();
tst1.join()
Tst tst2 = new Tst(1);
tst2.start();
tst1.join()
Tst tst3 = new Tst(2);
tst3.start();
}
You misunderstood the semantic of synchronized method, each one uses different lock object in your case, do it this way:
class SynchList {
private int sum = 0;
private final int MOD = 3;
private int compare;
private final int LIMIT = 1000;
private ArrayList<Integer> list = new ArrayList<Integer>();
public synchronized void populate( int compare) throws InterruptedException{
for(int i=0; i<=LIMIT; i++){
if (i%this.MOD == compare){
list.add(i);
}
}
}
public synchronized void sum( int compare ) throws InterruptedException{
for (Integer ger : list){
if (ger%MOD == compare){
sum+=ger;
}
System.out.println( sum );
}
}
}
class Tst extends Thread {
int compare;
SynchList synchList;
public Tst(int compare, SynchList synchList)
{
this.compare= compare;
this.synchList = synchList;
}
#Override
public void run(){
try {
synchList.populate( compare );
synchList.sum( compare );
} catch (InterruptedException ex) {
Logger.getLogger(Tst.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class Main
{
public static void main(String[] args) {
SynchList synchList = new SynchList();
Tst tst1 = new Tst( 0 , synchList );
tst1.start();
Tst tst2 = new Tst( 1, synchList );
tst2.start();
Tst tst3 = new Tst( 2, synchList );
tst3.start();
}
}
Your use of synchronized methods isn't doing what you think it's doing. The way your code is written, the methods "sum" and "populate" are protected
from running at the same time, but only on the same thread instance. That means calls to "sum" and "populate" for a single Tst object will happen one at a time,
but simultaneous calls to "sum" on different object instances will be allowed to happen concurrently.
Using synchronized on a method is equivalent to writing a method that is wrapped
with synchronized(this) { ... } around the entire method body. With three different instances created – tst1, tst2, and tst3 – this form of synchronization
doesn't guard across object instances. Instead, it guarantees that only one of populate or sum will be running at a time on a single object; any other calls to one of
those methods (on the same object instance) will wait until the prior one finishes.
Take a look at 8.4.3.6. synchronized Methods in the Java Language Specification
for more detail.
Your use of static might also not be doing what you think it's doing. Your code also shares things across all instances of the Tst thread class – namely, sum and list. Because these are defined as static,
there will be a one sum and one list. There is no thread safety in your code to guard against concurrent changes to either of those.
For example, as threads are updating
"sum" (with the line: sum+=ger), the results will be non-deterministic. That is, you will likely see different results every time you run it.
Another example of unexpected behavior with multiple threads and a single static variable is list – that will grow over time which can result in concurrency issues. The Javadoc says:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
Modifications include adding values as well as growing the backing array store. Without specifying a starting size – new ArrayList() – it will default to 10 or possibly some other relatively small number depending on which JVM version you're using. Once one thread tries to add an item that exceeds the ArrayList's capacity, it will trigger an automatic resize.
Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.
In my program, I want to create multiple threads in one of the methods where each thread has to run a specific method with a given input. Using Runnable, I have written this snippet.
class myClass {
public myClass() { }
public void doProcess() {
List< String >[] ls;
ls = new List[2]; // two lists in one array
ls[0].add("1"); ls[0].add("2"); ls[0].add("3");
ls[1].add("4"); ls[1].add("5"); ls[1].add("6");
// create two threads
Runnable[] t = new Runnable[2];
for (int i = 0; i < 2; i++) {
t[ i ] = new Runnable() {
public void run() {
pleasePrint( ls[i] );
}
};
new Thread( t[i] ).start();
}
}
void pleasePrint( List< String > ss )
{
for (int i = 0; i < ss.size(); i++) {
System.out.print(ss.get(i)); // print the elements of one list
}
}
}
public class Threadtest {
public static void main(String[] args) {
myClass mc = new myClass();
mc.doProcess();
}
}
Please note, my big code looks like this. I mean in one method, doProcess(), I create an array of lists and put items in it. Then I want to create threads and pass each list to a method. It is possible to define the array and lists as private class members. But, I want to do that in this way.
Everything seems to be normal, however, I get this error at calling pleasePrint():
error: local variables referenced from an inner class must be final or effectively final
pleasePrint( ls[i] );
How can I fix that?
The reason you are getting this error is straightforward and clearly mentioned - local variables referenced from an inner class must be final or effectively final. This is, in turn, because, the language specification says so.
Quoting Guy Steele here:
Actually, the prototype implementation did allow non-final variables
to be referenced from within inner classes. There was an outcry from
users, complaining that they did not want this! The reason was interesting: in order to support such variables, it was necessary to
heap-allocate them, and (at that time, at least) the average Java
programmer was still pretty skittish about heap allocation and garbage
collection and all that. They disapproved of the language performing
heap allocation "under the table" when there was no occurrence of the
"new" keyword in sight.
As far as your implementation goes, instead of using an array of list, I'd rather use a list of lists.
private final List<List<String>> mainList = new ArrayList<>();
You can create new lists and insert them into the main list in the constructor depending on the number of lists you want.
public ListOfLists(int noOfLists) {
this.noOfLists = noOfLists;
for (int i = 0; i < noOfLists; i++) {
mainList.add(new ArrayList<>());
}
}
You can then change your doProcess() method as follows:
public void doProcess() {
for (int i = 0; i < noOfLists; i++) {
final int index = i;
// Using Lambda Expression as it is much cleaner
new Thread(() -> {
System.out.println(Thread.currentThread().getName());
pleasePrint(mainList.get(index)); // Pass each list for printing
}).start();
}
}
Note: I used an instance variable named noOfLists to (as the name suggests) store the number of lists I need. Something as follows:
private final int noOfLists;
To populate the list, you could do:
mainList.get(0).add("1");
mainList.get(0).add("2");
mainList.get(0).add("3");
mainList.get(1).add("4");
mainList.get(1).add("5");
mainList.get(1).add("6");
// And so on...
And you'll get the output something as:
Thread-0
1
2
3
Thread-1
4
5
6
Hope this helps :)
First to that, you will get a NullPointerException here:
ls[0].add("1"); ls[0].add("2"); ls[0].add("3");
ls[1].add("4"); ls[1].add("5"); ls[1].add("6");
Before, yo must instantiate the lists:
ls[0] = new ArrayList<>();
ls[1] = new ArrayList<>();
About the compiler error, try to define the array as final. Change:
List< String >[] ls;
ls = new List[2]; // two lists in one array
By:
final List< String >[] ls = new List[2]; // two lists in one array
This is because you can't access to non-final (or effectively final) variables from a local class.
'ls' is effectively final but probably, since you have defined it in two lines, the compiler is not able to notice that.
I have written a method (part of a program) which takes in two int values(code below). One int value representing number of guys for whom java training is completed and another int value for guys for whom php training is completed. I expect the arraylist to grow with every function call. Example: First time I called the function with values (5,0). So the arrayList for java would be [5] and for php it would be [0] . Next time I call the function with values (2,3). The arrayList for java should now be [5][2] and sum should be 7. The the arraylist for php should be [0][3] ans sum should be 3. The problem with my code is that when I call the method for the second time, it wipes away the [5](value of first index from the first call) in the java arrayList and just takes the form of [2] and gives the sum 2(instead of the required 7). The arrayList is never growing. (same for the php arrayList) I am sure I am doing something conceptually wrong here . Please help Somehow, the way I have coded it, every function call seems to make a new arrayList and not growing the arrayList obtained from the previous call.
public class TrainingCamp {
public static int trainedJavaGuys ;
public static int trainedPHPGuys ;
public void trainedTroopsInCamp(int java,int php){
//System.out.println("********* Current Status of Training Camp ********* ");
ArrayList<Integer> trainingListJava = new ArrayList<>();
trainingListJava.add(java);
//System.out.println("---JavaARRAYLIST----"+trainingListJava);
trainedJavaGuys = sumList(trainingListJava);
ArrayList<Integer> trainingListPHP = new ArrayList<>();
trainingListPHP.add(php);
trainedPHPGuys = sumList(trainingListPHP);
//System.out.println("---phpARRAYLIST----"+trainingListPHP);
Calling it like this from another class:
TrainingCamp currentTrainingCamp = new TrainingCamp();
currentTrainingCamp.trainedTroopsInCamp(2, 0);
and next time the same two lines get executed with just the input params changed
The arraylists are reinitialized each time you call trainedTroopsInCamp() because they are declared within it.
You should make the arraylists member variables, so that they only get initialized once, in the class's constructor.
public class TrainingCamp {
public static int trainedJavaGuys ;
public static int trainedPHPGuys ;
// Declare once
ArrayList<Integer> trainingListJava;
ArrayList<Integer> trainingListPHP;
public TrainingCamp() {
// Initialize once
trainingListJava = new ArrayList<>();
trainingListPHP = new ArrayList<>();
}
public void trainedTroopsInCamp(int java,int php){
// Use everywhere
trainingListJava.add(java);
trainedJavaGuys = sumList(trainingListJava);
trainingListPHP.add(php);
trainedPHPGuys = sumList(trainingListPHP);
}
}
you're re-initializing the list references in the method call, so every time you call the method you're using a new (empty) list.
instead, try keeping the lists as member variables for your class, something like this:
class TrainingCamp {
private final List<Integer> javaTrained = new LinkedList<>();
private final List<Integer> phpTrained = new LinkedList<>();
public void trainedTroopsInCamp(int java,int php){
//System.out.println("********* Current Status of Training Camp ********* ");
javaTrained.add(java);
trainedJavaGuys = sumList(javaTrained);
phpTrained.add(php);
trainedPHPGuys = sumList(phpTrained);
}
...
}
I have a sequence of information being randomly generated. I would like to save that information in a variable of some kind so that it can be recalled elsewhere. i think I want to use an ArrayList, but I'm not sure how to add the information while inside a for loop (which is where it is being created). The code I have is as follows:
public static ArrayList<String> phoneList
public static void main(String[] args){
Random randomNumber = new Random();
int howMany = randomNumber.nextInt(11);;
String holding;
for (int i=0; i < howMany; i++){
int itemRandNum = randomNumber.nextInt(11);//for all Item Categories
int priceRandNum = randomNumber.nextInt(11);//Prices for all categories
holding = phones[itemRandNum]+" $"+ priceOfPhones[priceRandNum];
//System.out.println(holding);
phoneList.add("holding"); //here is where I would like to add the information
//contained in "holding" to the "phoneList" ArrayList.
}
System.out.println(phoneList);
}
I am getting a NullPointerException. If an ArrayList is not the best thing to use here, what would be?
Any help you can give is appreciated.
public static void String Main(String[] args) suggests this doesn't have much to do with Android.
First, instantiate the list (Outside your for loop):
phoneList = new ArrayList<>(howMany); //Adding "howMany" is optional. It just sets the List's initial size.
Then, add the values:
for (int i = 0; i < howMany; i++) {
//...
phoneList.add(holding);
//Don't place holding in quotation marks, else you'll just add "holding" for every entry!
}
You get a NullPointerException because ArrayList phoneList is null since you didn't initialize it. Therefore write
public static ArrayList<String> phoneList = new ArrayList<>();
As it is you are just declaring the class ArrayList not instantiating it. it is necessary for all the time you want to use a class to create an instance of the same class and thats simple, just do:
public static ArrayList phoneList = new ArrayList() (if you are running older versions of java), otherwise use public static ArrayList phoneList = new ArrayList<>().
I want to print elements of two arraylists with using two while conditions. But I get Concurrent Modification exception when trying to implement that.
What have I done wrong?
public void Insert_Answers(Enumeration<String> ques, Enumeration<String> ans){
try {
while(ans.hasMoreElements()){
String answer = ans.nextElement();
System.out.println(answer);
while(ques.hasMoreElements()){
String question = ques.nextElement();
System.out.println(question);
}
}
}
catch (Exception ex) {
Logger.getLogger(DbInsert.class.getName()).log(Level.SEVERE, null, ex);
}
}
This is the Test.java class where main method is contained
public class Test {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
DbInsert dbIns = new DbInsert();
ArrayList<String> arr1 = new ArrayList<String>();
arr1.add("a");
arr1.add("b");
arr1.add("c");
arr1.add("d");
Enumeration earr1 = Collections.enumeration(arr1);
ArrayList<String> arr2 = new ArrayList<String>();
arr2.add("e");
arr1.add("f");
arr1.add("g");
arr1.add("h");
Enumeration earr2 = Collections.enumeration(arr2);
dbIns.Insert_Answers(earr1, earr2);
}
}
My guess is you made a typo when populating arr2
arr2.add("e");
arr1.add("f");
arr1.add("g");
arr1.add("h");
you probably meant those adds to be to arr2
arr2.add("e");
arr2.add("f");
arr2.add("g");
arr2.add("h");
The concurrent modification error happens because you are adding to the backing List while the iteration is in progress.
I'm also not sure why you are using Enumeration. You should use Iterator instead.
Iterator<String> arr1Iter = arr1.iterator();
See this other SO question for why you should use Iterator instead : Difference between Java Enumeration and Iterator