Java实现多线程主要包括三种方式:
继承Thread类
实现Runnable接口
实现Callable接口
区别:
1.继承Thread类和实现Runnable方法启动线程都是使用start方法,然后JVM将此线程放到就绪队列,如果有处理机可用,则执行run方法。
2.实现Callable接口要实现call方法,并且线程执行完毕后会有返回值,其他两种重写run方法,没有返回值。
3.call()方法可抛出异常,而run()方法是不能抛出异常的。
4.实现Runnable和Callable接口还可以集成其他类,而继承Thread后不能再继承其他类
5.实现Runnable和Callable接口如果要访问当前线程,必须使用Thread.currentThread(),继承Thread类直接使用this即可获得当前线程、
1.Thread 类
class NewThread extends Thread{
public NewThread() {
// TODO Auto-generated constructor stub
System.out.println("创建子线程"+this);
}
@Override
public void run() {
// TODO Auto-generated method stub
try{
for(int i = 0;i<5;i++){
System.out.println("子线程->"+i);
this.sleep(100);
}
}catch (Exception e) {
// TODO: handle exception
}
System.out.println("退出子线程");
}
}
public class ThreadDemo{
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
NewThread newThread = new NewThread();
newThread.start();//启动子线程
System.out.println("主线程");
try{
for(int i = 0;i<5;i++){
System.out.println("主线程->"+i);
Thread.sleep(50);
}
}catch (Exception e) {
// TODO: handle exception
}
System.out.println("退出主线程");
}
}
运行结果:
上述代码可以看出,主线程设置的睡眠时间小于子线程,因此,主线程先于主线程完成,主线程退出后,子线程继续完成。主线程结束后,也可以调用stop方法结束子线程。也可以调用System.exit(0);强制退出进程。
2.Runnable接口
这里采用think in Java的例子。
class LifftOff implements Runnable{
protected int countdown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public LifftOff() {
// TODO Auto-generated constructor stub
}
public LifftOff(int countdown) {
this.countdown = countdown;
}
public String status(){
return "#"+id+"("+countdown+")";
}
@Override
public void run() {
// TODO Auto-generated method stub
while(countdown-->0){
System.out.print(status());
Thread.yield();//对线程调度器的一种建议,声明“我已经完成生命周期中最重要的组成部分了,此刻正是切换给其他任务执行一段时间的大好时机”
}
}
}
public class RunableDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
LifftOff lifftOff = new LifftOff();
lifftOff.run();
}
}
结果为:
将Runnable对象转变为工作任务的传统方式是把它提交给一个Thread构造器,下面用实例展示Thread来驱动LiftOff对象。
public class RunableDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i = 0;i<5;i++){
new Thread(new LifftOff()).start();
}
}
}
结果为:
由实验结果可以看出,不同任务的执行在线程换进换出时混在一起,这种线程交换是由线程调度器控制的,如果机器上有多个处理器,线程调度器将会在这些处理器之间默默分发线程。
3.Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class Calltest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
// TODO Auto-generated method stub
int sum = 0;
for(int i = 1;i<1000;i++){
sum = sum + i;
}
return sum;
}
}
public class CallableDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Calltest calltest = new Calltest();
//Callable方式需要FutureTask实现类的支持,用于接收运算结果
FutureTask<Integer> result = new FutureTask<Integer>(calltest);
new Thread(result).start();
try{
System.out.println(result.isDone());
Integer sum = result.get();//获取任务执行结果,如果任务未完成则阻塞等待直到任务完成
System.out.println(sum);
System.out.println(result.isDone()); }catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
结果为
FutrueTask(源自www.importnew.com/25286.html):
Future接口代表异步计算的结果,通过Future接口提供的方法可以查看异步计算是否执行完成,或者等待执行结果并获取执行结果,同时还可以取消执行。
- cancel():cancel()方法用来取消异步任务的执行。如果异步任务已经完成或者已经被取消,或者由于某些原因不能取消,则会返回false。如果任务还没有被执行,则会返回true并且异步任务不会被执行。如果任务已经开始执行了但是还没有执行完成,若mayInterruptIfRunning为true,则会立即中断执行任务的线程并返回true,若mayInterruptIfRunning为false,则会返回true且不会中断任务执行线程。
- isCanceled():判断任务是否被取消,如果任务在结束(正常执行结束或者执行异常结束)前被取消则返回true,否则返回false。
- isDone():判断任务是否已经完成,如果完成则返回true,否则返回false。需要注意的是:任务执行过程中发生异常、任务被取消也属于任务已完成,也会返回true
- get():获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常,如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。
- get(long timeout,Timeunit unit):带超时时间的get()版本,如果阻塞等待过程中超时则会抛出TimeoutException异常。
关于多线程中的Join
主要作用:同步,可以使得线程之间的并行执行变为串行执行。
如在上述的ThreadDemo中做出修改:
public class ThreadDemo{
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
NewThread newThread = new NewThread();
newThread.start();//启动子线程
System.out.println("主线程");
newThread.join();
try{
for(int i = 0;i<5;i++){
System.out.println("主线程->"+i);
Thread.sleep(50);
}
}catch (Exception e) {
// TODO: handle exception
}
System.out.println("退出主线程");
System.exit(0);
}
}
结果为:
Join的意思是放弃当前线程的执行,并返回相应的线程。
程序在Main线程中调用newThread线程的join方法,则main线程放弃CPU控制权,并返回newThread线程继续执行直到newThread执行完毕。因此直到newThread结束才返回主线程执行。
上述内容部分来源于网络和书本。