所以这是我的情况:
我真的不知道如何解决这个问题,而且在这方面我并不熟悉多线程和Java的API。
关于订购
我的意思是大约按顺序排列:如果它们按顺序启动,那就足够了。每个Runnable都会对地图的图块进行一些处理。我们的想法是以这样的方式对可运行物进行分类,首先加载在用户正在看的位置附近的瓦片,然后加载周围环境。请注意,因此执行顺序可能随时发生变化。
答案 0 :(得分:1)
一种解决方案是将您要处理的所有作业放入PriorityBlockingQueue。 (此队列使用队列项的自然顺序或提供比较器自动排序)。那么在ExecutorService中运行的线程应该只从队列中获取元素。
例如
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
public class PriorityQueueExample {
public static void main(String[] args) throws InterruptedException {
PriorityQueueExample priorityQueueExample = new PriorityQueueExample();
priorityQueueExample.doTheWork();
}
private void doTheWork() throws InterruptedException {
PriorityBlockingQueue<Customer> queue = new PriorityBlockingQueue<>(10, new CustomerComparator());
queue.add(new Customer("John", 5));
queue.add(new Customer("Maria", 2));
queue.add(new Customer("Ana", 1));
queue.add(new Customer("Pedro", 3));
while(queue.size() > 0){
System.out.println(queue.take());
}
}
}
class CustomerComparator implements Comparator<Customer> {
@Override
public int compare(Customer o1, Customer o2) {
return o1.getUrgency() - o2.getUrgency();
}
}
class Customer {
private String name;
private int urgency;
public Customer(String name, int urgency) {
this.name = name;
this.urgency = urgency;
}
public String getName() {
return name;
}
public int getUrgency() {
return urgency;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", urgency=" + urgency +
'}';
}
}
答案 1 :(得分:0)
1)让你的瓷砖实现Callable
。您也可以让他们返回Callable
。
2)确定哪些是首先要加载的位置。
3)将他们或Callable
传递给java.util.concurrent.ExecutorService.invokeAll
。
4)返回invokeAll
后,获取与前一个相邻的下一组图块,然后再次调用java.util.concurrent.ExecutorService.invokeAll
。
5)如有必要,重复步骤4.
答案 2 :(得分:0)
您还可以使用List来模拟优先级队列。例如:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListEmulateQueueExample {
public static void main(String[] args) throws InterruptedException {
ListEmulateQueueExample priorityQueueExample = new ListEmulateQueueExample();
priorityQueueExample.doTheWork();
}
/**
* uses a list to emulate a queue.
*/
private void doTheWork() {
List<Customer> customerList = Collections.synchronizedList(new ArrayList<>());
Customer johnCustomer = new Customer("John", 5);
Customer mariaCustomer = new Customer("Maria", 3);
Customer anaCustomer = new Customer("Ana", 1);
customerList.add(johnCustomer);
customerList.add(mariaCustomer);
customerList.add(anaCustomer);
CustomerComparator customerComparator = new CustomerComparator();
synchronized (customerList){
customerList.sort(customerComparator);
}
System.out.println(customerList.remove(0)); // Ana
johnCustomer.setUrgency(1);
synchronized (customerList){
customerList.sort(customerComparator);
}
System.out.println(customerList.remove(0)); // John
}
}
答案 3 :(得分:0)
所以,我终于解决了这个问题。它并不那么漂亮和善良,但它按预期工作。
这个想法是:如果每个Runnable都是无状态的并且只调用一个方法,那么它不需要知道它应该在创建时处理的tile。相反,一旦它启动,它将要求所需的磁贴。
public class WorldRendererGL {
protected Map<Vector2i, RenderedRegion> regions = new ConcurrentHashMap<>();
protected Queue<RegionLoader> running = new ConcurrentLinkedQueue<>();
protected Set<RenderedRegion> todo = ConcurrentHashMap.newKeySet();
protected ExecutorService executor;
/** Recalculate everything */
public void invalidateTextures() {
//Abort current calculations
running.forEach(f -> f.invalid.set(true));
running.clear();
todo.addAll(regions.values());
for (int i = 0; i < regions.size(); i++) {
RegionLoader loader = new RegionLoader();
running.add(loader);
executor.submit(loader);
}
}
protected class RegionLoader implements Runnable {
/** Set this to true to nullify all calculations*/
final AtomicBoolean invalid = new AtomicBoolean(false);
@Override
public void run() {
try {
if (invalid.get())
return;
RenderedRegion region = null;
region = nextRegion(); // Get the correct work at runtime
if (region == null)
return;
BufferedImage texture = renderer.renderRegion(new RegionFile(region.region.regionFile));
if (!invalid.get()) {
region.texture = texture;
update.notifyObservers();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
protected RenderedRegion nextRegion() {
Comparator<RenderedRegion> comp = (a, b) -> /*...*/);
RenderedRegion min = null;
for (Iterator<RenderedRegion> it = todo.iterator(); it.hasNext();) {
RenderedRegion r = it.next();
if (min == null || comp.compare(min, r) > 0)
min = r;
}
todo.remove(min);
return min;
}
}