本节开始java多线程编程的学习,对于操作系统、进程、线程的基本概念不再赘述,只是了解java对于多线程编程的支持有哪些。
一、继承Thread类来创建线程
java语言中使用Thread类来代表线程,代表线程的类可以通过继承Thread类并重写run()方法来实现多线程开发,调用线程类实例的start方法来启动该线程。下面来试一试
packageThreadTest;public class FirstThread extendsThread{private inti;public voidrun(){for(;i<100;i++){
System.out.println(getName()+ " "+i);
}
}public static voidmain(String[] args){for(int i = 0; i<10000 ; i++){//Thread.currentThread()方法,获取当前线程实例
System.out.println(Thread.currentThread().getName() + " " +i);if(i == 20){newFirstThread().start();newFirstThread().start();
}
}
}
}
输出结果可想而知,三个线程交替运行。其中mian线程是Thread-0 和 Thread-1的父亲线程,使用继承Thread类的线程类来创建线程时,多个线程无法共享线程类的实例变量。
二、实现Runnable接口来创建线程类
Runnable接口中只有一个抽象方法 void run(),是一个函数式接口。如果打开Thread类的代码,就可以发现Thread类也是实现了Runnable接口。
实现Runnable接口的run()方法的类只能算一个target,只是为线程提供了run方法,要真正创建线程必须调用Thread的构造方法来创建Thread,其实也是使用了Thread来创建线程。
下面来试一试
packageThreadTest;public class SecondThread implementsRunnable{private inti;public voidrun(){for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+ " " +i);
}
}public static voidmain(String[] args)
{for(int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+ " "+i);if(i==20){
Runnable st= newSecondThread();new Thread(st,"自定义名字").start();
}
}
}
}
这是Thread的run方法,可以看到Thread调用了Runnable实现类的run方法。
三、使用Callable 和 Future创建线程
Callable接口只有一个call()抽象方法,与run()不同的是call()有返回值,可以抛出异常
下图是Callable接口定义
泛型V代表了call方法的返回值类型
那么如何把实现了Callable接口的类的call方法当做线程执行体呢,如何获取call方法的返回值呢?
这需要用到Future,Future接口代表call()方法的返回值,调用Future实例的get方法可以去的返回值,对应于Callable接口,Future也支持泛型。
还需要用到FutureTask类,这个类实现了Future接口和Runnable,可以获取到返回值,也可以作为线程创建的target
FutureTask的构造器
FutureTask的run方法
下面用一下
packageThreadTest;importjava.util.concurrent.Callable;importjava.util.concurrent.Future;importjava.util.concurrent.FutureTask;public classThirdThread{public static voidmain(String[] args){
ThirdThread tt= newThirdThread();
FutureTask task = new FutureTask(new Callable() {
@Overridepublic Integer call() throwsException {int i =0;for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+ " " +i);
}returni;
}
});for (int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+i);if(i == 20){new Thread(task,"带返回值的线程").start();
}try{
System.out.println("子线程返回值:" +task.get());
}catch(Exception ex){
ex.printStackTrace();
}
}
}
}
这里要注意,调用FutureTask方法的get方法时,当前线程在取得返回值之前会被阻塞。
通常使用后两种方式来创建线程