62,621
社区成员
发帖
与我相关
我的任务
分享
package ThreadPool;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PoolTest
{
public static void main(String[] args) throws InterruptedException, ExecutionException
{
ExecutorService exe = Executors.newSingleThreadExecutor();
Set<Callable<String>> call = new HashSet<>();
call.add(new Callable<String>()
{
@Override
public String call() throws Exception
{
System.out.println("run1");
return "task1";
}
});
call.add(new Callable<String>()
{
@Override
public String call() throws Exception
{
System.out.println("run2");
return "task2";
}
});
call.add(new Callable<String>()
{
@Override
public String call() throws Exception
{
System.out.println("run3");
return "task3";
}
});
System.out.println(exe.invokeAny(call));
exe.shutdown();
}
}
/**
* the main mechanics of invokeAny.
*/
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future<T> f = ecs.poll();
if (f == null) {
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
else
f = ecs.take();
}
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
实际上调用的方法是由执行集合的iterator过程决定的,也就是第一个取得的Callable对象。
对于HashSet就也是依靠其hash散列的结果来决定的,如果你要测试这个过程,你可以重写hashCode方法,如:
@Override
public int hashCode(){
return 2;
}
Java并发包提供了诸多的快捷实现,调用invokeAny意图意味着,你要执行一个任务,该任务有多个实现方式,就是所谓的路径,
一旦一条路径达到终点,则取消其他的执行。而通常的hello world玩具式调用不具备这样的特性,所以也不用太纠结。找到场景才是学习多线程的有效方法。
public class RunMain1 {
public static void main(String[] args) throws ExecutionException,InterruptedException{
Set<Callable<String>> call = new HashSet<>();
call.add(new MyCallableA());
call.add(new MyCallableB());
call.add(new MyCallableC());
ExecutorService executorService = Executors.newSingleThreadExecutor();
System.out.println(executorService.invokeAny(call));
}
}
class MyCallableA implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("CallableA begin");
for (int i = 0; i < 5; i++) {
System.out.println("A:" + i);
}
System.out.println("CallableA end" );
return "call A";
}
}
class MyCallableB implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("CallableB begin");
for (int i = 0; i < 5; i++) {
System.out.println("B:" + i);
}
System.out.println("CallableB end");
return "call B";
}
}
class MyCallableC implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("CallableC begin");
for (int i = 0; i < 5; i++) {
System.out.println("C:" + i);
}
System.out.println("CallableC end");
return "call C";
}
}
输出结果:
CallableB begin
B:0
B:1
B:2
B:3
B:4
CallableB end
CallableA begin
call B
A:0
A:1
A:2
A:3
A:4
CallableA end