线程有多种实现的方式:
1.实现 Runnable 接口,实现run() 方法
2.继承Thread类,调用start() 方法
3.实现Callable 接口,实现call() 方法,和第一种 差不多,call 方法要抛出异常,run 不会
假设,我们现在有个通知数数的任务,从1-100。
public class Advice implements Runnable{
static int num = 1;
@Override
public void run() {
// 数数
while(num < 100){
System.out.println(num);
num ++;
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Advice a = new Advice();
a.run();
}
}
这里很简单,实现Runable run(),方法,和一个普通的方法差不多。但是这样没有任何特殊之处,必须要显示的将这个任务绑定到线程上,才能有效。下面看看Thread 这个线程类的做法。
public class ThreadTest {
public static void main(String[] args) {
Advice a = new Advice();
Thread t = new Thread(a);
t.start();
System.out.println("这是一个线程");
}
}
这里 你执行,你会 发现:“这是一个线程会先打印出来,为什么呢?”
Thread 构造器需要一个Runable 对象,调用start 为该线程执行初始化操作,然后调用Runable 的run方法。这里的打印语句在调用run()方法的前,就完成了,因为这其实是2个线程,其中一个是 mian(),他在调用Advice 的时候,是另外一个线程 Thread t ,去调用,不影响main()线程的继续执行,因此 很顺利的久执行下去了。这里说明线程 有调用其他线程的能力,并且“同时”执行。
这里同理,我们在main 线程里面创建5个线程,猜测结果?
public class ThreadTest {
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread(new Advice()).start();
System.out.println("这是一个线程");
}
}
}
如果你测试了,你就发现结果是每一次都不一样,是混乱的。这里建立5个不同的线程 进行测试更加明显
这里说明:不同任务的执行线程,混在一起的时候,是有线程调度自动控制,会分发给你的处理器分发执行。顺序是不确定的。
下面,我们看看java.unti.concurrent 包中的Executor ,管理你的线程,Executor 在客户端和任务执行时间提供了间接层,允许管理异步执行任务。看看源码和API 还是很好理解。
public class ThreadTest {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
exec.execute(new Advice());
System.out.println("这是一个线程:"+i);
}
exec.shutdown();
}
}
这里是ExecutorService 继承Executor,是具有生命周期的,可以关闭(shutdown)。Executor 提供单一方法 execute(Runanle commod),Executors 有点像工具类,提供了各种静态方法,比如:
newCachedThreadPool :相当于线程池,为每个任务都创建一个线程
newFixedThreadPool:也是线程池,但是可以给定默认的线程数,节约资源。和 StringBuffer(1024) 差不多
newSingleThreadExecutor:单一线程,准确的说是将多个任务,放入一个队列,然后按顺序执行。
可以去多建任务,进行尝试,其他的就自己看看API。
有时候我们任务需要及时的返回一个值,那么就可以用Callable 接口,看代码:
public class TaskWithResult implements Callable<String>{
private int id;
public TaskWithResult(int id){
this.id = id;
}
@Override
public String call() throws Exception {
return "result of TaskWithResult "+id;
}
}
public class ThreadTest {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
ArrayList<Future<String>> results = new ArrayList<Future<String>>();
for(int i = 0;i<10;i++){
Future<String> str = exec.submit(new TaskWithResult(i));
results.add(str);
}
for(Future<String> fs : results){
try {
System.out.println(fs.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally{
// 不关闭,任务不结束
exec.shutdown();
}
}
}
}
Future 对象是callable 方法返回的,特定的类型,进行了参数化。可以用isDone 来查询它是否完成,完成时,可以调用get()获得结果,如果不用isDone()进行检查,直接调用get(),会阻塞,直到结果准备就绪。