java 中的控制线程
controlling threads in java
我正在尝试创建一些东西,其中我必须提供两个可控线程,除了我可以启动、停止、暂停、恢复这些线程的主线程,我在抽象中提供了这些线程 class。这些线程将在后台执行它们中的一些专用功能。
目前我已经在其中创建了启动和停止功能,但我遇到了一个问题,即在第二次启动后调用停止功能时,它并没有停止。
我已经实现了将线程操作写入日志文件以对此进行测试,并观察到我第二次调用停止函数时,它卡在 while 循环中等待 运行 功能完成。
谁能帮我找出导致这个问题的原因,因为我对多线程处理不太陌生
下面是实施的 classes
控制器class,其中主线程和辅助线程应该被控制:
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;
}
}
测试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,刚刚实现以测试线程行为:
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,刚刚实施以测试线程行为:
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;
}
}
主日志的输出:
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
因为您正试图根据控制变量来控制两个线程。为这 4 个成员使用 volatile 关键字。
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?
我正在尝试创建一些东西,其中我必须提供两个可控线程,除了我可以启动、停止、暂停、恢复这些线程的主线程,我在抽象中提供了这些线程 class。这些线程将在后台执行它们中的一些专用功能。
目前我已经在其中创建了启动和停止功能,但我遇到了一个问题,即在第二次启动后调用停止功能时,它并没有停止。
我已经实现了将线程操作写入日志文件以对此进行测试,并观察到我第二次调用停止函数时,它卡在 while 循环中等待 运行 功能完成。
谁能帮我找出导致这个问题的原因,因为我对多线程处理不太陌生
下面是实施的 classes
控制器class,其中主线程和辅助线程应该被控制:
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;
}
}
测试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,刚刚实现以测试线程行为:
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,刚刚实施以测试线程行为:
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;
}
}
主日志的输出:
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
因为您正试图根据控制变量来控制两个线程。为这 4 个成员使用 volatile 关键字。
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?