0

I am trying to create something in which i have to provide two controllable threads apart from the main where i can start, stop, pause, resume these threads, which i am providing in an abstract class. These threads will perform some dedicated functions in them in the background.

Currently I have created start and stop functions in them, but i am facing an issue where on calling the stop function after staring it second time, it is not stopping.

I have implemented writing the thread operations to log file to test this, and observed that second time when i am calling the stop function, it is getting stuck up into the while loop which waits for the loop implemented in the run function to complete.

Can someone help me to figure out what is causing this issue, as i am little new to multithreading

Below are the classes implemented

Controller class in which Primary and Secondary threads should be controlled:

package com.threadcontrol;

import com.threadcontrol.TimeStampGenerator;

public abstract class Controller {      

    private static Thread threadPrim=null;
    private static Thread threadSec=null;
    private static Status statusPrim=Status.NOT_STARTED;    
    private static Status statusSec=Status.NOT_STARTED; 
    private static boolean completedPrim=false; 
    private static boolean completedSec=false;
    private static RunnablePrim runnablePrim=new RunnablePrim();
    private static RunnableSec runnableSec=new RunnableSec();
    private static Logger loggerPrim=new Logger("LogPrim.txt");
    private static Logger loggerSec=new Logger("LogSec.txt");

    public enum Status {NOT_STARTED, RUNNING, PAUSED, STOPPED};
    public enum ThreadID {PRIM,SEC}

    private static class RunnablePrim implements Runnable
    {           
        @Override
        public void run() 
        {
            while(statusPrim==Status.RUNNING)
            {               
                loggerPrim.log(TimeStampGenerator.get() + " Running Prim:");                
            }               
            completedPrim=true;         
        }           
    }

    private static class RunnableSec implements Runnable
    {           
        @Override
        public void run() 
        {           
            while(statusSec==Status.RUNNING)
            {               
                loggerSec.log(TimeStampGenerator.get() + " Running Sec:");              
            }               
            completedSec=true;          
        }           
    }


    public static synchronized boolean start(ThreadID threadID)
    {   
        switch(threadID)
        {
            case PRIM:
                if(threadPrim==null)
                {
                    threadPrim=new Thread(runnablePrim,"Primary Thread");
                }
                statusPrim=Status.RUNNING;
                threadPrim.start();
                return true;
            case SEC:
                if(threadSec==null)
                {
                    threadSec=new Thread(runnableSec,"Secondary Thread");
                }
                statusSec=Status.RUNNING;
                threadSec.start();
                return true;            
        }
        return false;
    }

    public static synchronized boolean stop(ThreadID threadID)
    {       
        switch(threadID)
        {
            case PRIM:              
                statusPrim=Status.STOPPED;              
                while(completedPrim!=true)
                {

                }
                completedPrim=false;
                threadPrim=null;                    
                return true;
            case SEC:
                statusSec=Status.STOPPED;
                while(completedSec!=true)
                {

                }
                completedSec=false;
                threadSec=null;             
                return true;
        }
        return false;
    }

}

Test Class:

package com.threadcontrol;

public class TestController {

    public static void main(String[] args) throws InterruptedException {

        int timeout=10;
        Logger logger=new Logger("LogMain.txt");

        logger.log(TimeStampGenerator.get() + " Starting Prim");
        Controller.start(Controller.ThreadID.PRIM);     
        Thread.sleep(timeout);
        logger.log(TimeStampGenerator.get() + " Starting Sec");
        Controller.start(Controller.ThreadID.SEC);
        Thread.sleep(timeout);
        logger.log(TimeStampGenerator.get() + " Stopping Prim");
        Controller.stop(Controller.ThreadID.PRIM);
        logger.log(TimeStampGenerator.get() + " Stopped Prim");
        Thread.sleep(timeout);
        logger.log(TimeStampGenerator.get() + " Stopping Sec");
        Controller.stop(Controller.ThreadID.SEC);
        logger.log(TimeStampGenerator.get() + " Stopped Sec");
        logger.log(TimeStampGenerator.get() + " Restarting");
        logger.log(TimeStampGenerator.get() + " Starting Prim");
        Controller.start(Controller.ThreadID.PRIM);     
        Thread.sleep(timeout);
        logger.log(TimeStampGenerator.get() + " Starting Sec");
        Controller.start(Controller.ThreadID.SEC);
        Thread.sleep(timeout);
        logger.log(TimeStampGenerator.get() + " Stopping Prim");
        Controller.stop(Controller.ThreadID.PRIM);
        logger.log(TimeStampGenerator.get() + " Stopped Prim");
        Thread.sleep(timeout);
        logger.log(TimeStampGenerator.get() + " Stopping Sec");
        Controller.stop(Controller.ThreadID.SEC);
        logger.log(TimeStampGenerator.get() + " Stopped Sec");
        logger.log(TimeStampGenerator.get() + " Exiting");

    }

}

Logger class, just implemented to test the threads behaviour:

package com.threadcontrol;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Logger {

    private static String projPath=System.getProperty("user.dir");
    private String filePath;

    public Logger(String fileName)
    {
        filePath=projPath + "\\data\\" + fileName;  
        File file=new File(filePath);
        try 
        {           
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file, false)));
            out.flush();
            out.close();
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void log(String data) 
    {           
        File file=new File(filePath);
        try 
        {           
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file, true)));
            out.println(data);
            out.close();
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
    }

}

TimeStampGenerator class, just implemented to test the threads behaviour:

package com.threadcontrol;

import java.text.SimpleDateFormat;
import java.util.Date;

public abstract class TimeStampGenerator {  

    public static String get()
    {
        Date currentTimeStamp=new Date();
        SimpleDateFormat fmt=new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS");
        String tsStr=fmt.format(currentTimeStamp);
        return tsStr;
    }
}

Output from main log:

2016_07_23_21_01_11_160 Starting Prim
2016_07_23_21_01_11_320 Starting Sec
2016_07_23_21_01_11_331 Stopping Prim
2016_07_23_21_01_11_333 Stopped Prim
2016_07_23_21_01_11_345 Stopping Sec
2016_07_23_21_01_11_346 Stopped Sec
2016_07_23_21_01_11_347 Restarting
2016_07_23_21_01_11_348 Starting Prim
2016_07_23_21_01_11_359 Starting Sec
2016_07_23_21_01_11_371 Stopping Prim
user3422841
  • 95
  • 1
  • 13
  • Well, for starters, nearly all of those instance variables in `Controller` should be moved into the thread class, and there should be only one thread class, not two. That would clean up your code a lot. – markspace Jul 23 '16 at 16:02

1 Answers1

1

Because you're trying to control two threads based on control variables. Use volatile keyword for these 4 members.

private static volatile Status statusPrim=Status.NOT_STARTED;    
private static volatile Status statusSec=Status.NOT_STARTED; 
private static volatile boolean completedPrim=false; 
private static volatile boolean completedSec=false;

Do you ever use the volatile keyword in Java?

Community
  • 1
  • 1
Happier
  • 838
  • 8
  • 21