* Java的新手
在Main中,它在遍历workItems之前调用processItems()。 问题是processItems()需要很长时间,例如10分钟
import java.lang.*;
import java.util.*;
import static java.util.stream.Collectors.*;
public class App {
private List<String> workItems;
private int factor = 0;
public App() {
workItems = new ArrayList<>();
//create some work in workItmes
workItems.add("apple");
workItems.add("oranges");
workItems.add("bananas");
}
public List<String> getWorkItems() {
return workItems;
}
public void calculateFactor() throws Exception{
// does some work which takes a long time
Thread.sleep(5*1000);
factor = 1;
}
public boolean evaluateItem(String item, int factor) {
// do some work based on item and current factor
System.out.println("Received: " + item + " " + factor);
return true;
}
public int getFactor() {
return factor;
}
public static void main(String[] args) throws Exception
{
App myApp = new App();
System.out.println("starting...");
int cnt = 0;
while (true) {
cnt++;
if (cnt > 5) {
break;
}
myApp.calculateFactor(); //<------- I dont want to call this here but in a background thread
int current_factor = myApp.getFactor();
List<Boolean> results = myApp.getWorkItems().stream().map(s -> myApp.evaluateItem(s, current_factor)).collect(toList());
System.out.println(results);
Thread.sleep(1*1000); // sleep a min
}
System.out.println("done");
}
}
我想将呼叫myApp.calculateFactor()
主要发送到后台线程
两件事情:此后台线程需要访问workItems并更新一个变量,该变量可通过getFactor()
对main可见
我在看ExecutorService executorService= Executors.newSingleThreadExecutor();
,但似乎没有一个教程暗示它可以看到线程的父级名称空间。
此外,如何清理背景螺纹?只是调用shutdown()?它如何处理中断?
答案 0 :(得分:1)
java.lang.Thread
JavaDoc给出了一个如何运行系统线程的示例。而且,JVM将执行GC。 Object.wait()
,Thread.sleep(..)
..可以获取系统中断信号。请注意并发数据访问,最好注意volatile
的使用情况,以防止某些内存不一致。下面来自JavaDoc
例如,计算素数大于指定值的线程可以编写如下:
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
然后,以下代码将创建一个线程并使其开始运行:
PrimeThread p = new PrimeThread(143);
p.start();
然后,Executors.newSingleThreadExecutor()
仅创建一个只有1个工作线程且工作队列为LinkedBlockingQueue
的ThreadPool。用作单例模式。通常,在服务器宕机后给钩子做一个shutdown()
。
答案 1 :(得分:1)
我认为我可以按以下方式工作,但是由于某种原因,即使在为执行者调用shutdown()之后,子线程也仍然挂起
private ExecutorService executor;
public App() {
workItems = new ArrayList<>();
//create some work in workItmes
workItems.add("apple");
workItems.add("oranges");
workItems.add("bananas");
executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
while (true) {
//Stopwatch stopwatch = Stopwatch.createStarted();
String threadName = Thread.currentThread().getName();
System.out.println("Hello " + threadName);
System.out.println("FROM THREAD: " + this.getWorkItems());
//this.incrementFactor(1);
try {
this.calculateFactor();
} catch (Exception e) {
//do nothing
}
try {
Thread.sleep(1*1000);
} catch (InterruptedException e) {
break;
}
}
});
}
答案 2 :(得分:1)
您确实可以像这样使用 Executors.newSingleThreadExecutor():
public class App {
private List<String> workItems;
private AtomicInteger factor = new AtomicInteger(0);
public App() {
workItems = new ArrayList<>();
//create some work in workItmes
workItems.add("apple");
workItems.add("oranges");
workItems.add("bananas");
}
public List<String> getWorkItems() {
return workItems;
}
public void calculateFactor() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
factor.set(1);
}
public boolean evaluateItem(String item, int factor) {
// do some work based on item and current factor
System.out.println("Received: " + item + " " + factor);
return true;
}
public AtomicInteger getFactor() {
return factor;
}
public static void main(String[] args) throws Exception {
App myApp = new App();
ExecutorService executorService = Executors.newSingleThreadExecutor();
System.out.println("starting...");
int cnt = 0;
while (true) {
cnt++;
if (cnt > 5) {
break;
}
executorService.submit(() -> {
try {
myApp.calculateFactor();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Error when calculating Factor");
}
});
int currentFactor = myApp.getFactor().get();
List<Boolean> results = myApp.getWorkItems().stream().map(s -> myApp.evaluateItem(s, currentFactor)).collect(toList());
System.out.println(results);
TimeUnit.SECONDS.sleep(1);
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("done");
}
}
此处executorService将运行一个新的Runnable,该Runnable仅运行您的方法calculateFactor。为了确保 factor 可以正确更新并由mainThread并行读取,可以使用专用于此类作业的AtomicInteger。关于关机和中断,最后应该做:
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS); // Time is arbitrary here. It depends your need
有关更多详细信息,请参见shutdown and awaitTermination which first call have any difference?。
在您的示例中,当我对其进行测试时,因数不变,因为您等待了5秒钟,线程calculateFactor等待了5秒钟,所以我的结果是:
starting...
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
done
但是如果我说cnt> 10,我会得到以下结果:
starting...
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
希望它能回答您的问题
添加::如果只想运行一次calculateFactor,则可以使用 countDownLatch 等待线程。示例:
public class App {
private List<String> workItems;
private AtomicInteger factor = new AtomicInteger(0);
private CountDownLatch countDownLatch = new CountDownLatch(1);
public App() {
workItems = new ArrayList<>();
//create some work in workItmes
workItems.add("apple");
workItems.add("oranges");
workItems.add("bananas");
}
public List<String> getWorkItems() {
return workItems;
}
public CountDownLatch getCountDownLatch() {
return countDownLatch;
}
public void calculateFactor() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
factor.set(1);
countDownLatch.countDown();
}
public boolean evaluateItem(String item, int factor) {
// do some work based on item and current factor
System.out.println("Received: " + item + " " + factor);
return true;
}
public AtomicInteger getFactor() {
return factor;
}
public static void main(String[] args) throws Exception {
App myApp = new App();
ExecutorService executorService = Executors.newSingleThreadExecutor();
System.out.println("starting...");
executorService.submit(() -> {
try {
myApp.calculateFactor();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Error when calculating Factor");
}
});
myApp.getCountDownLatch().await();
int currentFactor = myApp.getFactor().get();
List<Boolean> results = myApp.getWorkItems().stream().map(s -> myApp.evaluateItem(s, currentFactor)).collect(toList());
System.out.println(results);
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("done");
}
}
输出将是:
starting...
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
done
有关CountDownlLatch的更多详细信息:https://www.baeldung.com/java-countdown-latch