![](/img/trans.png)
[英]JAVA - Multithreading by Extending Thread Class - About Creating Objects
[英]Creating multithreading java class to process data
我想用Java实现类,该类将等待来自不同线程的新数据,当他得到它时,该类将对其进行处理,然后再次等待新数据。 我想仅使用同步,等待,notifyAll命令来实现这一点。 我尝试了一些变体:
1)使用一个线程,该线程通过命令lockObject.wait()等待。 但是,当所有活动线程完成工作时,该线程将永远等待。 当然,我可以使用stopProcess()方法,但这并不安全,因为另一个程序员可能会忘记调用它。
2)使用一个守护程序线程,它将无法工作,因为当所有活动线程完成工作后,我的守护程序线程将死亡,但他可以拥有一些必须处理的数据
3)当有新数据时-创建新线程,该线程将处理数据。 当线程处于活动状态时(他处理给定的数据),他将接收新数据。 当没有数据进入并且所有旧数据都已处理时,线程完成工作。 这个变体的缺点是-当数据经过一段时间(线程有时间处理旧数据并死亡时)时,将创建一个新线程。 我认为这对性能或/和内存不利。 我对吗?
是否可以仅使用一个或两个(可以同时使用守护程序和活动线程)线程而不使用stopProcess()方法来解决我的问题?
这里有一些代码
我对阻塞队列的认识
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
public void add(T el){
synchronized (queue){
queue.add(el);
}
}
public T getFirst(){
synchronized (queue){
return queue.poll();
}
}
public int getSize(){
synchronized (queue){
return queue.size();
}
}
}
资料类别
public class Data {
//some data
public void process(){
//process this data
}
}
代码的第一个变体
public class ProcessData {
private BlockingQueue<Data> queue = new BlockingQueue<Data>();
private boolean run = false;
private Thread processThread;
private Object lock = new Object();
public synchronized void addData(Data data) throws Exception {
if (run){
if (data != null){
queue.add(data);
wakeUpToProcess();
}
}else{
throw new Exception("");
}
}
public synchronized void start() {
if (!run){
run = true;
processThread = new Thread(new Runnable() {
public void run() {
while (run || queue.getSize()!=0){
while(queue.getSize() == 0 && run){
//if stopProcess was not called
//and no active threads
//it will not die
waitForNewData();
}
Data cur;
while(queue.getSize() > 0){
cur = queue.getFirst();
cur.process();
}
}
}
});
processThread.start();
}
}
public synchronized void stopProcess() {
if (run){
run = false;
wakeUpToProcess();
}
}
private void waitForNewData(){
try{
synchronized (lock){
lock.wait();
}
}catch (InterruptedException ex){
ex.printStackTrace();
}
}
private void wakeUpToProcess(){
synchronized (lock){
lock.notifyAll();
}
}
}
在第二个变体中,我将processThread作为守护程序。 但是,当活动线程死亡时,processThread完成工作,但是队列中有一些数据需要处理。
第三种变体
public class ProcessData {
private BlockingQueue<Data> queue = new BlockingQueue<Data>();
private boolean run = false;
private Thread processThread = null;
public synchronized void addData(Data data) throws Exception {
if (run){
if (data != null){
queue.add(data);
wakeExecutor();
}
}else{
throw new Exception("ProcessData is stopped!");
}
}
public synchronized void start() {
if (!run){
run = true;
}
}
public synchronized void stopProcess() {
if (run){
run = false;
}
}
public boolean isRunning(){
return this.run;
}
protected void wakeExecutor(){
if (processThread ==null || !processThread.isAlive()){
processThread = new Thread(new Runnable() {
@Override
public void run() {
Data cur;
while(queue.getSize() > 0){
cur = queue.getFirst();
cur.process();
}
}
});
processThread.start();
}
}
}
重要的是,数据必须按顺序来自线程的顺序进行处理。
您正在认真地在这里重新发明轮子。 您想要的所有内容都可以在JDK中的java.util.concurrent
包中找到 。
通过BlockingQueue实现生产者-消费者模式 ,您的生产者调用offer()
而您的消费者线程调用take()
,直到获得可用为止。
而已。 您不需要,也不应该编写所有已编写的类。 这些并发类为您执行了所有锁定和同步操作,并且也正确地执行了此操作(不要低估)
如果不允许使用java.util.concurrent
任何内容,则必须基于LinkedList
类实现自己的任务队列。 我将阻塞行为封装在队列中,例如(伪代码)
synchronized Data nextTask() {
while(the linked list is empty) {
wait()
}
remove and return head of the queue
}
synchronized void addTask(Data d) {
add d to the queue
notifyAll()
}
然后,您可以拥有一个消费者线程,该线程连续执行类似的操作
while(true) {
taskQueue.nextTask().process()
}
生产者线程调用taskQueue.addTask
将每个任务添加到队列中。 如果最后需要正常关机,则要么需要一些“前哨值”来告知使用者线程完成操作,要么可以找到在适当时间调用Thread.interrupt()
方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.