【重要】4线程汇总-线程间通信方式
1 callable和future
http://blog.csdn.net/zy_281870667/article/details/72047325
一般情况,我们实现多线程都是Thread或者Runnable(后者比较多),但是,这两种都是没返回值的,所以我们需要使用callable(有返回值的多线程)和future(获得线程的返回值)来实现了。
public class TestThread { public static void main(String[] args) { ThreadCount tc = null; ExecutorService es = Executors.newCachedThreadPool();//线程池 CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(es); for(int i=0;i<4;i++){ tc = new ThreadCount(i+1); cs.submit(tc); } // 添加结束,及时shutdown,不然主线程不会结束 es.shutdown(); int total = 0; for(int i=0;i<4;i++){ try { total+=cs.take().get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } System.out.println(total); } } class ThreadCount implements Callable<Integer>{ private int type; ThreadCount(int type){ this.type = type; } @Override public Integer call() throws Exception { if(type==1){ System.out.println("C盘统计大小"); return 1; }else if(type==2){ Thread.sleep(20000); System.out.println("D盘统计大小"); return 2; }else if(type==3){ System.out.println("E盘统计大小"); return 3; }else if(type==4){ System.out.println("F盘统计大小"); return 4; } return null; } }
ps:一个需要注意的小细节,cs.take.get()获取返回值(这里阻塞?),是按照完成的顺序的,即上面案例返回顺序是CEFD
tips:
ExecutorCompletionService 是将 Executor和BlockQueue结合的jdk类,其实现的主要目的是:提交任务线程,每一个线程任务直线完成后,将返回值放在阻塞队列中,然后可以通过阻塞队列的take()方法返回 对应线程的执行结果!!
2. join阻塞——直接用join把线程5加入进去即可
http://blog.csdn.net/u011971132/article/details/62444282
直接用join把线程5加入进去即可
public static void main(String[] args) throws InterruptedException
{
Thread t1 = new Thread(new Worker("thread-1"));
Thread t2 = new Thread(new Worker("thread-2"));
Thread t3 = new Thread(new Worker("thread-3"));
Thread t4 = new Thread(new Worker("thread-4"));
Thread t5 = new Thread(new Worker("thread-5"));
t1.start();t2.start();t3.start();t4.start();
t1.join();t2.join();t3.join();t4.join();
t5.start();
t5.join();
}
或者,在t5的run:
t1.start();t2.start();t3.start();t4.start(); t1.join();t2.join();t3.join();t4.join();
t5线程中等待四个线程返回
3.用java.util.concurrent下的方法解决
http://blog.csdn.net/wenwen360360/article/details/62104612
用CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行
CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.
4. ExecutorService类提供其他版本的invokeAll()阻塞——这还是一个更详细future的例子,其机制类似于join,这里拿出来
线程执行者(六)运行多个任务并处理所有结果
http://ifeve.com/thread-executors-6/
执行者框架允许你在不用担心线程创建和执行的情况下,并发的执行任务。它还提供了Future类,这个类可以用来控制任务的状态,也可以用来获得执行者执行任务的结果。
如果你想要等待一个任务完成,你可以使用以下两种方法:
- 如果任务执行完成,Future接口的isDone()方法将返回true。——注意,是立即返回,不会阻塞等待
- ThreadPoolExecutor类的awaitTermination()方法使线程进入睡眠,直到每一个任务调用shutdown()方法之后完成执行。
这两种方法都有一些缺点。第一个方法,你只能控制一个任务的完成。第二个方法,你必须等待一个线程来关闭执行者,否则这个方法的调用立即返回。
ThreadPoolExecutor类提供一个方法,允许你提交任务列表给执行者,并且在这个列表上等待所有任务的完成。在这个指南中,你将学习如何使用这个特性,实现一个示例,执行3个任务,并且当它们完成时将结果打印出来。
准备工作…
这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。
如何做…
按以下步骤来实现的这个例子:
1.创建Result类,存储这个示例中并发任务产生的结果。
1 |
public class Result
{ |
2.声明两个私有属性。一个String属性,名为name,另一个int属性,名为value。
1 |
private String
name; |
2 |
private int value; |
3.实现相应的get()和set()方法,用来设置和获取name和value属性的值。
01 |
public String
getName() { |
02 |
return name; |
03 |
} |
04 |
public void setName(String
name) { |
05 |
this .name
= name; |
06 |
} |
07 |
public int getValue()
{ |
08 |
09 |
return value; |
10 |
} |
11 |
public void setValue( int value)
{ |
12 |
this .value
= value; |
13 |
} |
4.创建Task类,实现Callable接口,参数化为Result类型。
1 |
public class Task implements Callable<Result>
{ |
5.声明一个私有String属性,名为name。
1 |
private String
name; |
6.实现Task类构造器,初始化这个属性。
1 |
public Task(String
name) { |
2 |
this .name=name; |
3 |
} |
7.实现这个类的call()方法,在本例中,它将返回一个Result对象。
1 |
@Override |
2 |
public Result
call() throws Exception
{ |
8.首先,写入一个信息到控制台,表明任务开始。
1 |
System.out.printf( "%s:
Staring\n" , this .name); |
9.然后,等待一个随机时间。
1 |
try { |
2 |
long duration=( long )(Math.random()* 10 ); |
3 |
System.out.printf( "%s:
Waiting %d seconds for results.\n" , this .name,duration); |
4 |
TimeUnit.SECONDS.sleep(duration); |
5 |
} catch (InterruptedException
e) { |
6 |
e.printStackTrace(); |
7 |
} |
10.在Result对象中返回一个计算5个随机数的总和的int值。
1 |
int value= 0 ; |
2 |
for ( int i= 0 ;
i< 5 ;
i++){ |
3 |
value+=( int )(Math.random()* 100 ); |
4 |
} |
11.创建Result对象,用任务的名称和前面操作结果来初始化它。
1 |
Result
result= new Result(); |
2 |
result.setName( this .name); |
3 |
result.setValue(value); |
12.写入一个信息到控制台,表明任务已经完成。
1 |
System.out.println( this .name+ ":
Ends" ); |
13.返回Result对象。
1 |
return result; |
2 |
} |
14.最后,实现这个示例的主类,创建Main类,实现main()方法。
1 |
public class Main
{ |
2 |
public static void main(String[]
args) { |
15.使用Executors类的newCachedThreadPool()方法,创建ThreadPoolExecutor对象。
1 |
ExecutorService
executor=(ExecutorService)Executors.newCachedThreadPool(); |
16.创建Task对象列表。创建3个Task对象并且用这个列表来存储。
1 |
List<Task>
taskList= new ArrayList<>(); |
2 |
for ( int i= 0 ;
i< 3 ;
i++){ |
3 |
Task
task= new Task(i); |
4 |
taskList.add(task); |
5 |
} |
17.创建Future对象列表,参数化为Result类型。
1 |
List<Future<Result>>resultList= null ; |
18.调用ThreadPoolExecutor类的invokeAll()方法。这个类将会返回之前创建的Future对象列表。
1 |
try { |
2 |
resultList=executor.invokeAll(taskList); |
3 |
} catch (InterruptedException
e) { |
4 |
e.printStackTrace(); |
5 |
} |
19.使用shutdown()方法结束执行者。
1 |
executor.shutdown(); |
20.写入处理Future对象列表任务的结果。
01 |
System.out.println( "Main:
Printing the results" ); |
02 |
for ( int i= 0 ;
i<resultList.size(); i++){ |
03 |
Future<Result>
future=resultList.get(i); |
04 |
try { |
05 |
Result
result=future.get(); |
06 |
System.out.println(result.getName()+ ":
" +result. |
07 |
getValue()); |
08 |
} catch (InterruptedException
| ExecutionException e) { |
09 |
e.printStackTrace(); |
10 |
} |
11 |
} |
它是如何工作的…
在这个指南中,你已经学习了如何提交任务列表到执行者和使用invokeAll()方法等待它们的完成。这个方法接收Callable对象列表和返回 Future对象列表。这个列表将会有列表中每个任务的一个Future对象。Future对象列表的第一个对象是Callable对象列表控制的第一个任务,以此类推。
第一点要考虑的是,在存储结果对象的列表中声明的Future接口参数化的数据类型必须与使用的Callable对象的参数化相兼容。在本例中,你已经使用相同数据类型:Result类型。
另一个重要的一点就是关于invokeAll()方法,你会使用Future对象获取任务的结果。当所有的任务完成时,这个方法结束,如果你调用返回的Future对象的isDone()方法,所有调用都将返回true值。
不止这些…
ExecutorService类提供其他版本的invokeAll()方法:
- invokeAll(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit):此方法执行所有任务,当它们全部完成且未超时,返回它们的执行结果。TimeUnit类是个枚举类,有如下常量:DAYS,HOURS,MICROSECONDS, MILLISECONDS, MINUTES,,NANOSECONDS 和SECONDS。