Results 1 to 13 of 13
  1. #1
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Multithreading problem from tortoise and hare theme

    Below is the code for a tortoise and hare. 2 threads are instantiated and started... What I want is that when one reaches 1000 meters, it says I finished and calls the finished(); but I can't get it to call the finished(); as it's in another class. I want that finished method to also determine which thread called it and then interrupt the other thread. I've been looking at the code, and it does not work. Thanks for the help.


    public class marathonRace {
    /**
    * @param args
    */

    public static Thread tortoise;
    public static Thread hare;

    public static void main(String[] args) {

    tortoise = new ThreadRunner("Tortoise", 0, 10);
    hare = new ThreadRunner("Hare", 90, 100);

    System.out.println("Get set... Go!");
    tortoise.start();
    hare.start();
    }

    public static synchronized void finished(Thread winner) {

    System.out.println("name of the thread " + winner.getName());

    if(winner.equals(hare))
    {
    System.out.println("The race is over, hare wins");
    tortoise.interrupt();

    }
    if(winner.equals(tortoise))
    {
    System.out.println("The race is over, tortoise wins");
    hare.interrupt();
    }

    }
    }



    class ThreadRunner extends Thread {
    private String name;
    private int restValue, speed;

    ThreadRunner(String Name, int RestValue, int Speed) {
    name = Name;
    restValue = RestValue;
    speed = Speed;
    }

    public void run() {
    int distance = 0;
    while (!isInterrupted() && distance < 1000) {
    try {
    int rand = (int) (Math.random() * 100);
    if (restValue <= rand) {
    distance += speed;
    System.out.println(name + " : " + distance);
    }
    Thread.sleep(100);
    }
    catch (InterruptedException e){
    System.out.println(name+": You won fare and square!");
    break;
    }
    }
    System.out.println(name + ": I finished!");
    marathonRace.finished(Thread.currentThread());
    }
    }

  2. #2
    jashburn is offline Senior Member
    Join Date
    Feb 2014
    Posts
    219
    Rep Power
    1

    Default Re: Multithreading problem from tortoise and hare theme

    Please wrap your code with [code] tags so that it is easier to read, e.g.,
    [code=java]
    // your code here
    [/code]

    It preserves formatting and provides syntax highlighting, e.g.,
    Java Code:
    // your code here
    You actually have almost got it except for one thing. The main thing is when tortoise.interrupt() or hare.interrupt() is called, it most likely (but in theory, not always - do you know why?) cause an InterruptedException to be thrown during Thread.sleep(100) in ThreadRunner's run() method. When this happens, it is caught by
    Java Code:
    catch (InterruptedException e) {
        System.out.println(name + ": You won fare and square!");
        break;
    }
    It breaks out of the while loop, and goes on to incorrectly execute
    Java Code:
    System.out.println(name + ": I finished!");
    marathonRace.finished(Thread.currentThread());
    The above should only be executed when the while loop terminates because distance is 1000 or more.

    To fix this you can add an if statement to check if the loop was terminated due to an interrupt or if distance is 1000 or more. Note that in this case you cannot use the isInterrupted() method to check for the former. The sleep() method's API doc states,

    "InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown."

    I.e., isInterrupted() will return false once the exception is thrown due to the auto-clearing of the interrupted status. Therefore you'll be better off checking for the latter (distance).

    A few other minor points:

    1. Naming a thread

    If you take a look at the Thread class' API doc, you'll find that it has some constructors that take in a string for its name. The advantage of naming a thread is with a call like "System.out.println(name + " : " + distance)", you'll get a proper name rather than something like "Thread-0".

    2. Class and method parameter naming

    By convention, Java class names begin with an uppercase character (e.g., MarathonRace rather than marathonRace), and parameter names begin with a lowercase character (e.g., "ThreadRunner(String name, int restValue, int speed)" rather than "ThreadRunner(String Name, int RestValue, int Speed)".) By sticking to this convention, it makes it obvious which is which when other people read your code.

    3. "Fair and square"

    Not "fare".

  3. #3
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    class ThreadRunner extends Thread {
    private String name;
    private int restValue, speed;

    ThreadRunner(String Name, int RestValue, int Speed) {
    name = Name;
    restValue = RestValue;
    speed = Speed;
    }

    public void run() {
    int distance = 0;
    while (!isInterrupted() && distance < 1000) {
    try {
    int rand = (int) (Math.random() * 100);
    if (restValue <= rand) {
    distance += speed;
    System.out.println(name + " : " + distance);
    }
    Thread.sleep(100);
    }
    catch (InterruptedException e){
    System.out.println(name + ": You beat me fair and square." + "\n");
    break;
    }
    }
    if(distance >= 1000)
    {
    System.out.println(name + ": I finished!" + "\n");
    MarathonRace.finished(Thread.currentThread(), name);
    }
    }
    }


    public class MarathonRace {
    /**
    * @param args
    */

    public static Thread tortoise;
    public static Thread hare;
    public static Thread dog;

    public static void main(String[] args) {

    tortoise = new ThreadRunner("Tortoise", 0, 10);
    hare = new ThreadRunner("Hare", 90, 100);
    dog = new ThreadRunner("Dog", 50, 20);

    System.out.println("Get set... Go!");
    tortoise.start();
    hare.start();
    dog.start();
    }



    public static synchronized void finished(Thread winner, String winnerName) {


    if(winner.equals(hare))
    {
    System.out.println("The race is over! The hare is the winner" + "\n");
    tortoise.interrupt();
    dog.interrupt();
    }
    if(winner.equals(tortoise))
    {
    System.out.println("The race is over! The tortoise is the winner" + "\n");
    hare.interrupt();
    dog.interrupt();
    }
    if(winner.equals(dog))
    {
    System.out.println("The race is over! The dog is the winner" + "\n");
    tortoise.interrupt();
    hare.interrupt();
    }
    }


    }


    [/code]


    Thank you.

  4. #4
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    Jashburn,

    Thank you very much for your quick and detailed replied. I do really appreciate it. I made the changes as you pointed out, and it works. Now, I am trying to generalize this code for "n" animals. Right now, I just hard coded 3 animals to see how the code works. It seems, it works, but the output in the console is not 100% reliable. Here, I am attaching a partial output form one of the runs:


    Tortoise : 990
    Dog : 860
    Tortoise : 1000
    Hare : 800
    Dog : 880
    Dog : 900
    Tortoise: I finished!

    The race is over! The tortoise is the winner

    Hare: You beat me fair and square.

    Dog: You beat me fair and square.


    As you can see: "Hare : 800" , "Dog : 880", "Dog : 900" should not be there once Tortoise finished the race. I also noticed a couple of times that the "You beat me fair and square" message for the animals who lost the race did not showed up in the console at all. Do you know why? Is it the natural way of processing threads? Is it anyway to "tight" this thread behavior? Let me know please. Here, I am also attaching my latest code:

    Java Code:
    class ThreadRunner extends Thread {
        private String name;
        private int restValue, speed;   
         
        ThreadRunner(String Name, int RestValue, int Speed) {
            name = Name;
            restValue = RestValue;
            speed = Speed;
        }
         
        public void run() {
            int distance = 0;
            while (!isInterrupted() && distance < 1000) {
                try {
                    int rand = (int) (Math.random() * 100);
                    if (restValue <= rand) {             
                        distance += speed;
                        System.out.println(name + " : " + distance);
                    }       
                    Thread.sleep(100);
                }
                catch (InterruptedException e){
                	System.out.println(name + ": You beat me fair and square." + "\n");
                    break;
                }
            }
            if(distance >= 1000)
            {
            	System.out.println(name + ": I finished!" + "\n");
            	MarathonRace.finished(Thread.currentThread(), name);
            }
        }
    }
    
    
    public class MarathonRace {
        /**
         * @param args
         */
    	
    	public static Thread tortoise;
    	public static Thread hare;
    	public static Thread dog;
    	
        public static void main(String[] args) {
            
        	tortoise = new ThreadRunner("Tortoise", 0, 10);
        	hare = new ThreadRunner("Hare", 90, 100);
        	dog = new ThreadRunner("Dog", 50, 20);
             
            System.out.println("Get set... Go!");
            tortoise.start();
            hare.start();
            dog.start();
        }
        
        
        
        public static synchronized void finished(Thread winner, String winnerName) {
        	
       	
        	if(winner.equals(hare))
            {
        		System.out.println("The race is over! The hare is the winner" + "\n");
        		tortoise.interrupt();
        		dog.interrupt(); 
            }
            if(winner.equals(tortoise))
            {
            	System.out.println("The race is over! The tortoise is the winner" + "\n");
            	 hare.interrupt();
            	 dog.interrupt();    	              
            }
            if(winner.equals(dog))
            {
             	System.out.println("The race is over! The dog is the winner" + "\n");
             	tortoise.interrupt();
             	hare.interrupt();        	              
            }
        }
        
        
    }

    Thank you.

  5. #5
    jashburn is offline Senior Member
    Join Date
    Feb 2014
    Posts
    219
    Rep Power
    1

    Default Re: Multithreading problem from tortoise and hare theme

    Quote Originally Posted by littleluis View Post
    Tortoise : 990
    Dog : 860
    Tortoise : 1000
    Hare : 800
    Dog : 880
    Dog : 900
    Tortoise: I finished!

    The race is over! The tortoise is the winner

    Hare: You beat me fair and square.

    Dog: You beat me fair and square.


    As you can see: "Hare : 800" , "Dog : 880", "Dog : 900" should not be there once Tortoise finished the race.
    This is an indication of a race condition. The key part of the code is
    Java Code:
    public void run() {
        int distance = 0;
        while (!isInterrupted() && distance < 1000) {
            try {
                int rand = (int) (Math.random() * 100);
                if (restValue <= rand) {
                    distance += speed;
                    System.out.println(name + " : " + distance);
                }
                Thread.sleep(100);
            }
            catch (InterruptedException e) {
                System.out.println(name + ": You beat me fair and square." + "\n");
                break;
            }
        }
        if (distance >= 1000) {
            System.out.println(name + ": I finished!" + "\n");
            MarathonRace.finished(Thread.currentThread(), name);
        }
    }
    With multithreaded code, you typically need to examine your code very closely, and imagine what happens when the same bit of code is executed concurrently. In your case you have 3 threads running the above code at the same time. When the first thread's distance reaches 1000, it:
    • prints out the name and distance
    • sleeps for 100 ms
    • checks the while conditions to determine if it needs to iterate one more time

    In the meantime other threads are still running and may have time to print out their names and distances, especially if they reach "System.out.println(name + " : " + distance)" right after the first thread.

    Try moving "Thread.sleep(100)" from the bottom of the while loop to the top of the loop, and work out how might this help. A technique to use when you have trouble visualising concurrent execution is to put your code into a flow chart, and print 2 copies of it. Trace the execution on the chart with your left- and right-hand fingers to simulate concurrent execution for 2 threads.

    Quote Originally Posted by littleluis View Post
    I also noticed a couple of times that the "You beat me fair and square" message for the animals who lost the race did not showed up in the console at all. Do you know why?
    I believe this is related to what I wrote previously,
    "The main thing is when tortoise.interrupt() or hare.interrupt() is called, it most likely (but in theory, not always - do you know why?) cause an InterruptedException to be thrown during Thread.sleep(100) in ThreadRunner's run() method."

    When a thread is interrupted, there are 2 things in ThreadRunner's while loop that stops the thread:
    1. Thread.sleep(100): causes an InterruptedException to be thrown, which then breaks out of the while loop in the catch block
    2. isInterrupted(): this is 1 of the conditions checked in the while loop that causes the loop to terminate if this method returns true (and negated by the ! operator)

    Therefore, if the thread's interrupted status is set, not during "Thread.sleep(100)", but right before isInterrupted() is called, you will not see the "You beat me fair and square" message that is in the catch block since the loop terminates without having an InterruptedException raised.

  6. #6
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    jasburn,

    Thank you for your time and explanations. I made some changes in my code, but I still have the problem I stated before. The changes I did is about having an array list of threads. That way, I can have "n" runners later on, and I also changed a little bit the concept of when the thread should rest or not. But the output in console when I run it is not always reliable. I am wondering if you can modify the code to solve this enigma. I would really appreciate it. I tried to implement the concept of:

    Java Code:
    private static object syncObject = new Object();
    
    public void run()
    {
    synchronized (syncObject) {
    // some of my code
    }
    }
    but it did not work.

    Here I am attaching my new code. I would appreciate your help, and see how you do it. That, I will learn. Thank you very much.

    Java Code:
    class ThreadRunner extends Thread {
    	
    	public static final int MARATHON_DISTANCE = 1000;
    	
    	
        private String runnersName;
        private int restPercentage, runnersSpeed;   
         
        ThreadRunner(String name, int speed, int restTime) {
        	runnersName = name;
        	restPercentage = restTime;
            runnersSpeed = speed;
        }
         
        
        public String getRunnersName() {
    		return runnersName;
    	}
    
    	public void setRunnersName(String runnersName) {
    		this.runnersName = runnersName;
    	}
    
    	public int getRestPercentage() {
    		return restPercentage;
    	}
    
    	public void setRestPercentage(int restPercentage) {
    		this.restPercentage = restPercentage;
    	}
    
    	public int getRunnersSpeed() {
    		return runnersSpeed;
    	}
    
    
    	public void setRunnersSpeed(int runnersSpeed) {
    		this.runnersSpeed = runnersSpeed;
    	}
        
        
        public void run() {
            int distance = 0;
            
            
            	while (!isInterrupted() && distance < MARATHON_DISTANCE) {
            		try
            		{
            			
            			int randonNumber = (int) (Math.random() * 101);
            			if (randonNumber <= restPercentage) //Thread rests if random is less or equal to restTime
            			{             
            				Thread.sleep(100);
            			}
            			else
            			{
            				distance += runnersSpeed;
            				System.out.println(runnersName + " : " + distance);
            			}
                        
            		}
            		catch (InterruptedException e){
            			System.out.println(runnersName + ": You beat me fair and square." + "\n");
            			break;
            		}
            	}
            	
            	if(distance >= MARATHON_DISTANCE)
            	{
            		System.out.println(runnersName + ": I finished!" + "\n");
            		MarathonRace.finished(Thread.currentThread(), runnersName);
            	}
               
            
        }
    
    
    
    
    
    	
        
    }
    
    
    import java.util.ArrayList;
    
    
    public class MarathonRace {
        
    	
    	
    	public static ArrayList<ThreadRunner> runningThreads = new ArrayList<>();
    	
        public static void main(String[] args) {
        	
    
            
        	runningThreads.add(new ThreadRunner("Tortoise", 10, 10));
        	runningThreads.add(new ThreadRunner("Hare", 100, 90));
        	runningThreads.add(new ThreadRunner("Dog", 50, 40));
        	runningThreads.add(new ThreadRunner("Cat", 30, 75));
    		
             
            System.out.println("Get set... Go!");
            
            
            for(int i = 0; i < runningThreads.size(); i++ )
    		{
            	runningThreads.get(i).start();	
    		}
        }
        
        
        
         
        public static synchronized void finished(Thread winner, String winnerName) {
          	
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println("The race is over! The " + winnerName + " is the winner" + "\n");  			
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			runningThreads.get(i).interrupt();
    		}  	
        }
        
    }

  7. #7
    jashburn is offline Senior Member
    Join Date
    Feb 2014
    Posts
    219
    Rep Power
    1

    Default Re: Multithreading problem from tortoise and hare theme

    Sorry, I was engaged with some other work for the past few days. Have you been able to resolve this? If not, have you tried anything else other than what you've got in your last post?

  8. #8
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    Hi Jushburn. Nice hearing from you again. I tried to make some changes in the code, but I do believe I am still getting some race conditions once in a while. For a moment, it seems it is working, but after running the code several times, it produces dome unlikable output like the ones I showed you before:

    ....

    Dog : 750
    Lion : 700
    Lion : 750
    Cat : 120
    Cat : 150
    Dog : 800
    Dog : 850
    Dog : 900
    Dog : 950
    Dog : 1000
    Dog: I finished!

    Tortoise : 240
    The race is over! The Dog is the winner

    Tortoise: You beat me fair and square.

    Hare: You beat me fair and square.

    Cat: You beat me fair and square.

    Lion: You beat me fair and square.

    Press Enter to continue


    Java Code:
    import java.util.ArrayList;
    
    class ThreadRunner extends Thread {
    	
    	public static final int MARATHON_DISTANCE = 1000;
    	
    	
        private String runnersName;
        private int restPercentage, runnersSpeed;
        private volatile int distance;
        private MarathonRace myMarathonRace = new MarathonRace();
    
        //Constructors
        ThreadRunner(){
        	runnersName = "";
        	restPercentage = 0;
            runnersSpeed = 0;   	
        }
        
        
        ThreadRunner(String runnersName, int runnersSpeed, int restPercentage)
        {
        	this.runnersName = runnersName;
        	this.restPercentage = restPercentage;
            this.runnersSpeed = runnersSpeed;
        }
         
        // Getter
        public String getRunnersName() {
    		return runnersName;
    	}
        
        //Setter
        public void setRunnersName(String runnersName) {
    		this.runnersName = runnersName;
    	}
        
        public void setRestPercentage(int restPercentage) {
    		this.restPercentage = restPercentage;
    	}
        
        public void setRunnersSpeed(int runnersSpeed) {
    		this.runnersSpeed = runnersSpeed;
    	}
        
       
        
        public void run() {  
            	while (!isInterrupted() && distance < MARATHON_DISTANCE) {
            		try
            		{
            			
            			int randonNumber = (int) (Math.random() * 101);
            			if (randonNumber <= restPercentage) //Thread rests if random is less or equal to restTime
            			{             
            				Thread.sleep(100);
            			}
            			else
            			{
            				distance += runnersSpeed;
            				System.out.println(runnersName + " : " + distance);
            			}
                        
            		}
            		catch (InterruptedException e){
            			break;
            		}
            	}
            	
            	if(distance >= MARATHON_DISTANCE)
            	{
            		System.out.println(runnersName + ": I finished!" + "\n");
            		myMarathonRace.finished(Thread.currentThread(), runnersName);
            	}
               
            
        }
    
    }
    
    
    
    
    
    
    public class MarathonRace {
        
    	
    	
    	public static ArrayList<ThreadRunner> runningThreads = new ArrayList<>();
    	
    	
        public static void main(String[] args) {
        	
        	MarathonRace myMarathonRace = new MarathonRace();
        	
        	
       		
        		runningThreads.add(new ThreadRunner("Tortoise", 20, 40));
        		runningThreads.add(new ThreadRunner("Hare", 100, 90));
        		runningThreads.add(new ThreadRunner("Dog", 50, 40));
        		runningThreads.add(new ThreadRunner("Cat", 30, 75));
        		runningThreads.add(new ThreadRunner("Lion", 50, 40));
        	
    		
             
        		myMarathonRace.runThreadsConcurrent();
        		runningThreads.clear();
        		
        		myMarathonRace.hitEntertoContinue();
        		
        		
        		 
    
        
        }
        
        
        private void runThreadsConcurrent()
        {
        	System.out.println("Get set... Go!");
            
            
    		for(int i = 0; i < runningThreads.size(); i++ )
    		{
    			runningThreads.get(i).start();	
    		}
    		
    		for(int i = 0; i < runningThreads.size(); i++ )
    		{
    			try
    			{
    				runningThreads.get(i).join();
    			}
    			catch(InterruptedException e) {
    		        e.printStackTrace();
    		    }
    
    		}
        }
        
        private void hitEntertoContinue()
        {
        	System.out.println("Press Enter to continue");  
    		try
    		{
    			System.in.read();
    		}  
    		catch(Exception e){} 
        }
        
        
        
        public  synchronized void finished(Thread winner, String winnerName) {   	
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println("The race is over! The " + winnerName + " is the winner" + "\n");  			
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			runningThreads.get(i).interrupt();
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println(runningThreads.get(i).getRunnersName() + ": You beat me fair and square." + "\n");  			
    		}
        }
        
    }

    Any suggestions? Do you see or you can change something is this code to make it thread safe? Let me know please. I would really appreciate it. Thank you.

  9. #9
    jashburn is offline Senior Member
    Join Date
    Feb 2014
    Posts
    219
    Rep Power
    1

    Default Re: Multithreading problem from tortoise and hare theme

    Yes, there are indeed a few things that can be changed. In order to guarantee that you will not get the erroneous output, you need to identify the key areas whose execution need to be synchronised (to be done in a certain order) between the threads. This is where the flow chart I mentioned in my previous post helps. In your case, the key areas are at the parts of code that:
    1. prints the animal's running distance
    2. determines if the animal has completed the race

    The first thing to do is to see if the above areas can be placed together... and you can, e.g.,
    Java Code:
    distance += runnersSpeed;
    System.out.println(runnersName + " : " + distance);
    
    if (distance >= MARATHON_DISTANCE) {
        System.out.println(runnersName + ": I finished!" + "\n");
        myMarathonRace.finished(Thread.currentThread(), runnersName);
    }
    In order to synchronise the above areas, look for an object that is common to all the threads. A candidate is the ThreadRunner class object.

    (Digression: If you're unsure what a "class object" is, see Class (Java Platform SE 7 ) and the discussion at what is Class Object(java.lang.class) in java? - Stack Overflow)

    You can do this to synchronise against the class object:
    Java Code:
    synchronized (getClass()) {
        distance += runnersSpeed;
        System.out.println(runnersName + " : " + distance);
    
        if (distance >= MARATHON_DISTANCE) {
            System.out.println(runnersName + ": I finished!" + "\n");
            myMarathonRace.finished(Thread.currentThread(), runnersName);
        }
    }
    If you examine the above closely, you'd see that it is synchronised up to and including myMarathonRace.finished() that goes on to interrupt all the other threads. When this method returns, the other threads' interrupt status will be set. Therefore in order to avoid printing any of the other threads' running distance, you'll also need to add a check to find out if the thread has been interrupted right upon entering the synchronized block, i.e.,
    Java Code:
    synchronized (getClass()) {
        if (isInterrupted()) {
            break;
        }
    
        distance += runnersSpeed;
        System.out.println(runnersName + " : " + distance);
    
        if (distance >= MARATHON_DISTANCE) {
            System.out.println(runnersName + ": I finished!" + "\n");
            myMarathonRace.finished(Thread.currentThread(), runnersName);
        }
    }
    There are a few other structural but not-thread-affecting issues. E.g.,
    Quote Originally Posted by littleluis View Post
    Java Code:
        public  synchronized void finished(Thread winner, String winnerName) {   	
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println("The race is over! The " + winnerName + " is the winner" + "\n");  			
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			runningThreads.get(i).interrupt();
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println(runningThreads.get(i).getRunnersName() + ": You beat me fair and square." + "\n");  			
    		}
        }
    The first loop is unnecessary, and the latter 2 loops can be combined.

    Besides that, each ThreadRunner instance creates a new MarathonRace instance. I can see that you did it so that you can call "myMarathonRace.finished(Thread.currentThread( ), runnersName);" from any of the ThreadRunner instances. A better way would be to pass a callback reference to the MarathonRace object when ThreadRunner is being instantiated, e.g.,
    Java Code:
    runningThreads.add(new ThreadRunner("Tortoise", 20, 20, myMarathonRace));

  10. #10
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    Hi Jushburn,

    Thank you for you great feedback. I just focused to change the run() method as you suggested. I think it works nicely. But I do believe I still have a problem. If I go to the basics: Tortoise and Hare only. When Tortoise move 10 meters and never rests (value = 0), the only I see in my prints out in the console is the Tortoise only moves and the Hare does not looks like. I know tortoise always wins but the other (Hare) should also move once in a while. It seems there is something wrong yet. What do you think? Is any part of the code that it is not fully in sync yet? This is my latest code:





    Java Code:
    
    import java.util.ArrayList;
    
    
    class ThreadRunner extends Thread {
    	
    	public static final int MARATHON_DISTANCE = 1000;
    	
    	
        private String runnersName;
        private int restPercentage, runnersSpeed;
        private volatile int distance;
        private MarathonRace myMarathonRace = new MarathonRace();
    
        //Constructors
        ThreadRunner(){
        	runnersName = "";
        	restPercentage = 0;
            runnersSpeed = 0;   	
        }
        
        
        ThreadRunner(String runnersName, int runnersSpeed, int restPercentage)
        {
        	this.runnersName = runnersName;
        	this.restPercentage = restPercentage;
            this.runnersSpeed = runnersSpeed;
        }
         
        // Getter
        public String getRunnersName() {
    		return runnersName;
    	}
        
        //Setter
        public void setRunnersName(String runnersName) {
    		this.runnersName = runnersName;
    	}
        
        public void setRestPercentage(int restPercentage) {
    		this.restPercentage = restPercentage;
    	}
        
        public void setRunnersSpeed(int runnersSpeed) {
    		this.runnersSpeed = runnersSpeed;
    	}
        
       
        
        public void run() {  
            	while (!isInterrupted() && distance < MARATHON_DISTANCE) {
            		try
            		{
            			
            			int randonNumber = (int) (Math.random() * 101);
            			if (randonNumber <= restPercentage) //Thread rests if random is less or equal to restTime
            			{             
            				Thread.sleep(100);
            			}
            			else
            			{
            				synchronized (getClass()) {
            				    if (isInterrupted()) {
            				        break;
            				    }
            				 
            				    distance += runnersSpeed;
            				    System.out.println(runnersName + " : " + distance);
            				 
            				    if (distance >= MARATHON_DISTANCE) {
            				        System.out.println(runnersName + ": I finished!" + "\n");
            				        myMarathonRace.finished(Thread.currentThread(), runnersName);
            				    }
            				}
            			}
                        
            		}
            		catch (InterruptedException e){
            			break;
            		}
            	}
                 	    
        }
    
    }
    
    
    
    
    
    
    
    
    public class MarathonRace {
        
    	
    	
    	public static ArrayList<ThreadRunner> runningThreads = new ArrayList<>();
    	
    	
        public static void main(String[] args) {
        	
        	MarathonRace myMarathonRace = new MarathonRace();
        	
        	
       		
        		runningThreads.add(new ThreadRunner("Tortoise", 10, 0));
        		runningThreads.add(new ThreadRunner("Hare", 100, 90));
        		//runningThreads.add(new ThreadRunner("Dog", 50, 40));
                //runningThreads.add(new ThreadRunner("Cat", 30, 75));
               // runningThreads.add(new ThreadRunner("Lion", 50, 40));
    
        		
        	
    		
             
        		myMarathonRace.runThreadsConcurrent();
        		runningThreads.clear();
        		
        		myMarathonRace.hitEntertoContinue();
        		
        		
        		 
    
        
        }
        
        
        private void runThreadsConcurrent()
        {
        	System.out.println("Get set... Go!");
            
            
    		for(int i = 0; i < runningThreads.size(); i++ )
    		{
    			runningThreads.get(i).start();	
    		}
    		
    		for(int i = 0; i < runningThreads.size(); i++ )
    		{
    			try
    			{
    				runningThreads.get(i).join();
    			}
    			catch(InterruptedException e) {
    		        e.printStackTrace();
    		    }
    
    		}
        }
        
        private void hitEntertoContinue()
        {
        	System.out.println("Press Enter to continue");  
    		try
    		{
    			System.in.read();
    		}  
    		catch(Exception e){} 
        }
        
        
        
        public  synchronized void finished(Thread winner, String winnerName) {   	
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println("The race is over! The " + winnerName + " is the winner" + "\n");  			
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			runningThreads.get(i).interrupt();
    		}
        	for(int i = 0; i < runningThreads.size(); i++ )
    		{
        		if(!winnerName.equals(runningThreads.get(i).getRunnersName()))
        			System.out.println(runningThreads.get(i).getRunnersName() + ": You beat me fair and square." + "\n");  			
    		}
        }
        
    }

  11. #11
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    Jushburn,

    From my latest code I just sent to you, I just modified the run() method a little bit:

    Java Code:
    public void run() {  
            	while (!isInterrupted() && distance < MARATHON_DISTANCE) {
            		try
            		{
            			synchronized (getClass()) {
            			int randonNumber = (int) (Math.random() * 101);
            			System.out.println("The thread name is: " + runnersName + " and the random number is " + randonNumber + " " + Thread.currentThread());
            			if (randonNumber <= restPercentage) //Thread rests if random is less or equal to restTime
            			{             
            				Thread.sleep(100);
            			}
            			else
            			{
            				 
            				    if (isInterrupted()) {
            				        break;
            				    }
            				 
            				    distance += runnersSpeed;
            				    System.out.println(runnersName + " : " + distance);
            				 
            				    if (distance >= MARATHON_DISTANCE) {
            				        System.out.println(runnersName + ": I finished!" + "\n");
            				        myMarathonRace.finished(Thread.currentThread(), runnersName);
            				    }
            				
            			}
            			} 
            		}
            		catch (InterruptedException e){
            			break;
            		}
            	}
                 	    
        }
    I inserted a System.out.println(....) to see the name of the thread and random number generated at any moment. This is a test just for tortoise and hare. I know there is a thread scheduler in java that I cannot control. But my question here is why the "Tortoise" thread is being called much more than "Hare" thread. It seems the code I wrote is not totally "neutral" in the way threads are called. Do you have any idea what it is happening? Thank you.

  12. #12
    jashburn is offline Senior Member
    Join Date
    Feb 2014
    Posts
    219
    Rep Power
    1

    Default Re: Multithreading problem from tortoise and hare theme

    The enlargement of the synchronized block in post #11 has made the program run with almost-constant thread contention:
    Quote Originally Posted by littleluis View Post
    Java Code:
    public void run() {  
        while (!isInterrupted() && distance < MARATHON_DISTANCE) {
            try
            {
                synchronized (getClass()) {
                    int randonNumber = (int) (Math.random() * 101);
                    [...]
                    if (randonNumber <= restPercentage) //Thread rests if random is less or equal to restTime
                    {             
                        Thread.sleep(100);
                    }
                    else
                    {
                         [...]
                        
                    }
                } 
            }
            catch (InterruptedException e){
                break;
            }
    It should be obvious from the above that the class-level lock (from synchronized (getClass())) is held throughout the sleep period when the lock should have been released for other threads to execute. The 100 ms sleep period is quite long relative to the other operations. You should revert it to the way it was in post #10.

    I don't think there is a problem with the code in post #10. It's just that the hare sleeps too much and too long (100 ms)! Add the following println()s to show what's happening:
    Java Code:
    public void run() {
        while (!isInterrupted() && distance < MARATHON_DISTANCE) {
            System.out.println("i  " + runnersName + " iterates");
            try {
    
                int randonNumber = (int) (Math.random() * 101);
                if (randonNumber <= restPercentage) // Thread rests if random is less or equal to
                                                    // restTime
                {
                    System.out.println("s  " + runnersName + " sleeps");
                    Thread.sleep(100);
                }
    You should that the hare thread does iterate, but almost always sleeps while the tortoise zooms ahead while the hare is sleeping.

  13. #13
    littleluis is offline Member
    Join Date
    Jun 2014
    Posts
    8
    Rep Power
    0

    Default Re: Multithreading problem from tortoise and hare theme

    Hi Jashburn,

    Thank you for your reply. As you suggested, I reverted my code as in post #10, a I added the System.out.println's as suggested. So, I can check the iterations of every thread. In addition, just for checking purposes, I also set Thread.sleep(1). Basically I tried to set the minimum "sleeping" time and see what happens. The results puzzled me. I was expecting to see the hare thread more "active". When I run the code, Hare iterates a couple of times approx, and tortoise is iterating the rest of the times. I know tortoise almost never sleeps unless the random number generated is zero, but hare sleeps only 1 millisecond. Is still 1 millisecond a long time? I still do not get why hare iterates so little. Let me know if I am missing something please. Thank you.

Similar Threads

  1. How to Commit to tortoise SVN Using JAVA
    By deshmukh.niraj04 in forum New To Java
    Replies: 1
    Last Post: 09-07-2011, 05:38 PM
  2. Java Multithreading Problem
    By avirit1983 in forum Threads and Synchronization
    Replies: 3
    Last Post: 12-03-2010, 11:18 PM
  3. MultiThreading Problem part 2
    By ravjot28 in forum New To Java
    Replies: 33
    Last Post: 03-11-2010, 07:22 PM
  4. MultiThreading Problem
    By ravjot28 in forum New To Java
    Replies: 8
    Last Post: 03-02-2010, 01:23 PM
  5. problem using ObjectOutputStream in multithreading
    By sanjeevbindroo in forum Networking
    Replies: 3
    Last Post: 10-15-2009, 09:00 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •