我还没有能够找到适合我的问题的答案,希望我能在这里找到一个可以指引我正确方向的人。
我试图让程序动态创建类实例和线程,并处理结束它们,并在允许更多启动之前清除内存。
我写的程序涉及访问大量设备,有时是定期访问。我需要一种适当的方法来跟踪线程,用户命令启动它们,并排队等待它们不会溢出内存。
用户可以选择结束可能包含许多线程的任务,因此我需要能够对该组进行全面删除。
我认为Arraylist是最好的,但是如下所示,我需要3个列表来协同工作,包括名称,类实例和线程。
public Class implements Runnable {
private inner class doThings implements Runnable {
public bool active = true
public bool done(){
return true;
}
public run() {
while (active){
x=1+1
}
public void instakill(){
active = false;
}
}
public void mainLoop() {
int maxThreads = 50
List names;
List instances;
List threads;
while true {
for (each request) {
if (threads.size < maxThreads ) {
names.add("unique name")
instances.add(new doThings())
threads.add(new Thread(instances.size - 1))
threads.get(Threads.size - 1).start
}
}
for (each instance) {
if (doThings.done()){
int arrayID = instance.getIndex
names.remove(arrayID)
instances.remove(arrayID)
threads.remove(arrayID)
trim-All-Lists-To-Size();
}
}
}
因此,主循环将创建类doThings的新实例,以及唯一的名称和运行该类的线程。这些被放入单独的,未链接的阵列中。我匹配它们的唯一方法是通过获取一个数组中的任何索引并计算,因为我从统一的所有数组中添加和对象,它应该是所有的相同索引。有点像填充3杯独立的水,并期望它们处于同一水平。
当然,除非它不是如何发挥作用。
如果我知道如何组合3位信息(名称,实例,线程),我可能不会遇到这个问题吗?
我是否应该将所有内容封装到更大的类中并保留其中的ArrayLists(或CopyOnWriteArrayLists)?
我不确定解决这个问题的正确方法是什么
感谢您的帮助!!
答案 0 :(得分:0)
正如Peter所建议的那样,你应该明确考虑使用ExecutorService
API而不是基于线程管理开发类似的机制。
尽管如此,关于您的原始代码,我认为您的难度实际上与线程管理无关,而只是与Java中的数据结构有关。不是并行维护三个不同的列表,最常见的方法只是将三个信息封装在某个内部类的实例中(例如Entry
),然后只有一个这些Entry
的列表(也就是说,在现代Java中:List<Entry>
)。
另一件需要知道的事情是,除非使用迭代器的remove方法,否则在迭代该集合时,永远不会删除集合中的元素;如果你这样做,你最终会得到ConcurentModificationException
。正确的方法是在集合上显式创建迭代器(例如list.iterator()
)然后迭代它(使用iterator.hasNext()
和iterator.next()
),最后使用`iterator.remove删除元素( )。
例如,您的代码可能如下所示:
public class ParentClass {
private class RunningInstanceEntry {
public String name;
public Worker worker;
public Thread thread;
}
private class Worker implements Runnable {
public boolean active = true;
public boolean done() {
return true;
}
public run() {
while (active) {
x = 1+1;
}
}
public void instakill() {
active = false;
}
}
public void mainLoop() {
int maxThreads = 50;
List<RunningInstanceEntry> instances =
new ArrayList<RunningInstanceEntry>();
while (true) {
for (R request : requests) {
if (threads.size < maxThreads) {
RunningInstanceEntry instance =
new RunningInstanceEntry();
instance.name = "unique name";
instance.worker = new Worker();
instance.thread = new Thread(instance.worker);
instance.thread.start();
instances.add(instance);
}
}
Iterator<RunningInstanceEntry> iterator =
instances.iterator();
while (iterator.hasNext()) {
RunningInstanceEntry instance = iterator.next();
if (instance.worker.done()) {
iterator.remove();
}
}
}
}
}
注意:此代码中还有很多其他改进机会,我个人认为不认为它有一个良好编码实践的例子。尽管如此,我仍然倾向于不要偏离原始代码,因为我的目标是强调使用仅结构类和iterator.remove()
方法。
答案 1 :(得分:0)
感谢您的建议!
以下是我将要实施的简写版本:
public class frontpage implements Runnable {
private class Monitor implements Runnable {
private String x;
public Monitor(String x) {
this.x = x;
}
@Override
public void run() {
System.out.println("monitor task " + x);
ConcurrentHashMap<String, Batch> batchlist = new ConcurrentHashMap<>();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
ScheduledFuture<?> countdown = null;
for (int i = 0; i < 10; i++) {
batchlist.put("monitor " + i, new Batch(
"monitor task " + Integer.toString(i)));
}
for (String key : batchlist.keySet()) {
countdown = scheduler.schedule(batchlist.get(key), 5, TimeUnit.SECONDS);
}
while (!countdown.isDone()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
scheduler.shutdown();
System.out.println("monitor " + x + "completed");
}
}
private class Batch implements Runnable {
private String x;
public Batch(String x) {
this.x = x;
}
@Override
public void run() {
ConcurrentHashMap<String, Task> tasklist = new ConcurrentHashMap<>();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
ScheduledFuture<?> countdown = null;
for (int i = 0; i < 10; i++) {
tasklist.put("task " + i, new Task(
"batch task " + Integer.toString(i)));
}
for (String key : tasklist.keySet()) {
countdown = scheduler.schedule(tasklist.get(key), 5, TimeUnit.SECONDS);
}
while (!countdown.isDone()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
scheduler.shutdown();
}
}
private class Task implements Runnable {
private String x;
public Task(String x) {
this.x = x;
}
@Override
public void run() {
System.out.println(x + " task completed");
}
}
public static void main(String args[]) {
frontpage thisone = new frontpage();
thisone.run();
}
@Override
public void run() {
//run once
Task once = new Task("once");
once.run();
//batch
Batch batch = new Batch("batch");
batch.run();
//monitor
Monitor monitor = new Monitor("monitor");
monitor.run();
}
}