Using Runnable to run a method by multiple threads - java

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.

Related

Is there a way to loop execute a method while passing a different instance of a class to it each time?

My current code looks something like this:
public void myMethod()
{
instance1.myPanel.setVisible();
instance2.myPanel.setVisible();
instance3.myPanel.setVisible();
instance4.myPanel.setVisible();
//A bunch more
instance57.myPanel.setVisible();
}
Is there a ways to shorten it?
The Code below obviously doesn't work but gives you an idea of what I'm trying to do:
public void myMethod2(myClass instance1)
{
instance1.myPanel.setVisible();
}
int i = 1;
while(i <= 57)
{
myMethod2("instance" + i);
i++
}
In practice, this kind of problem is normally handled using some sort of collection, and its use will often fit naturally into the initialization of a program with a large number of objects. Rather than hand-writing the creation of 57 similar objects, one line at a time, you would create them in a loop, adding them to a collection as you do so.
A List implementation like ArrayList would be a good choice here, or one could simply use an array.
With a List:
/* During initialization of your program somewhere. */
List<MyClass> instances = new ArrayList<>();
for (int i = 0; i < 57; ++i) {
instances.add(new MyClass());
}
...
/* Later when you need to invoke a method: */
instances.forEach(instance -> instance.myPanel.setVisible());
You can build a list of your vars and just go through them:
List<ClassType> list = Arrays.asList( obj1, ob2, obj3 );
list.forEach( instance -> instance.myPanel.setVisible() );

ConcurrentModificationException when trying to sum numbers of an Arraylist using multiple threads in Java

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.

Looping thread arraylist

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.

ArrayList getting reinitialized everytime the method is called

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);
}
...
}

Initialising/Creating Objects through a constructor

Ok so I'm doing an assignment for my java coursets part I'm stuck at is :
"Implement an operation createparliamentMembers which will create the particular Parliament
with 80 members."
So i've already created the constructor with it's methods. This is how I wrote the operation to create the objects using the constructor.:
public static void createparliamentMembers(){
Member[] array = new Member[75];
for(int i = 0; i < array.length; i++)
{
if (i < 35) array[i] = new Member(i, "Blue");
else array[i] = new Member(i,"Red");
}
Legislator[] leg = new Legislator[3];
for (int i = 0 ; i < leg.length; i++){
leg[i] = new Legislator(i, "Impartial");
}
Leader[] lead = new Leader[2];
for (int t = 0; t < lead.length; t++){
if (t < 1) lead[t] = new Leader(1, "Red");
else lead[t] = new Leader(2, "Blue");
}
The problem is the arrays and objects only seem to exist in the operation for creating them and when I try running method of the objects created they don't work because the driver class doesn't recognize the arrays. On the other hand when I use this as just a normal part of the Driver for it runs fine and all methods of the objects work normally.
Edit: Ok so I'm still getting the same problem as before even though i initiliased them outside the createparliamentMembers();
The following code is the Driver im using to test the methods: It keeps saying there is a:
Exception in thread "main" java.lang.NullPointerException at Driver.main(Driver.java:11)
which is the code array[1].FlipCoin(); as im trying to use the method flipcoin from the created objects but it's not working.
public static void main(String [] args) {
Commands.createparliamentMembers();
array[1].FlipCoin();
}
Your arrays are only defined locally, which means they live and die with the method. When your method finishes, they get put out of memory.
The solution is to define these arrays as instance variables. By that I mean, you need to define the arrays for your class, and then use them in your method:
class someClass {
int[] myArray = new int[2];
private void someMethod() {
myArray[0] = 3;
myArray[1] = //whatever
}
}
You state in comment:
I do have a parliament class it's on it own and contains the methods and constructor for the members of the parliament. The above method was in a seprate class called Commands. I don't understand completely the "Can you add the members to a Parliament object as you create them?" The parliament isn't an object more se then a class containing a constructor and methods for parliament members i want to create.
Parliament isn't an object yet, but you should in fact create one, and in fact your instructions tell you just that: "which will create the particular Parliament with 80 members...". You will need to tell us more about your program's structure and your specific requirements, but I suggest:
First create a Parliament object in the createParliamentMembers method, and call it parliament.
Then create the members of parliament in that method.
As you create these members, add them to the Parliament object, parliament.
At the end of the method return the parliament variable.
This means that your createParliamentMembers method's signature must change so that rather than return void it should be written to return a Parliament object.
When calling the method in the main method, assign what it returns to a Parliament variable that is in the main method.
It looks like you are writing a factory method. Create a constructor for Parliament like this:
public Parliament(Member[] members, Legislator[] legislators, Leader[] leaders) {
// do whatever with what's passed in
}
Then change your method to return a Parliament object and in the method pass your initialized arrays into the Parliament constructor, like this:
// same code as your except the last line
public static Parliament createParliament(){
Member[] array = new Member[75];
for(int i = 0; i < array.length; i++)
{
if (i < 35) array[i] = new Member(i, "Blue");
else array[i] = new Member(i,"Red");
}
Legislator[] leg = new Legislator[3];
for (int i = 0 ; i < leg.length; i++){
leg[i] = new Legislator(i, "Impartial");
}
Leader[] lead = new Leader[2];
for (int t = 0; t < lead.length; t++){
if (t < 1) lead[t] = new Leader(1, "Red");
else lead[t] = new Leader(2, "Blue");
}
return new Parliament(array, leg, lead);
}

Categories