三种Java创建线程的方式(Callable,FutureTask)

Java线程具有并发性和异步性,可以说线程是轻量级别的进程,java中线程和现代操作系统中的进程调度都是采用采用抢占式运行。但线程和进程最大的区别是:一个进程中的多个进程共享这个进程的内存空间和系统资源,但是进程之间是有独立的代码段和数据段。
下面介绍三种Java创建线程的方式:

1.  通过继承Thread类创建线程

2.  通过实现Runnable接口来创建线程

3.  通过实现Callable接口利用TaskFutrue来创建线程,当然也可以配合ExecutorServic来使用

接着说明下这三种方式创建线程的区别:
1.继承Thread类创建的线程可以拥有自己独立的类成员变量,但是实现Runnable接口创建线程共享实现接口类的成员变量。两中方式创建线程都要重写run方法,run方法是线程的执行体。
2.在继承Thread类创建进程中可以通过使用this获得当前进程的对象,但是在实现Runnable接口创建线程的途径中可以使用Thread.currentThread()方式来获得当前进程。
3.第三中方式是较为复杂的一种。Callable接口是一个与Runnable接口十分相似的接口。在Runnable中run方法为线程的执行体,但是在Callable接口中call方法是线程的执行体。下面是两个接口实现执行体的不同:
    (1).    call方法有返回值,但是run方法没有
    (2).    call方法可以生命抛出异常
所以可以说Callable接口是Runnable接口的增强版本
4.FutureTask类实现了Runnable和Future接口。和Callable一样都是泛型。
5.Future接口是对Callable任务的执行结果进行取消,查询是否完成,获取结果的。下面是这个接口的几个重要方法:
    (1).    boolean cancel(boolean myInterruptRunning) 
            试图取消Future与Callable关联的任务
    (2).    V get()
            返回Callable任务中call方法的返回值,调用该方法会导致程序阻塞,必须等到子线程结束才会有
            返回值。这里V表示泛型
    (3).    V get(long timeout, TimeUnit    unit)
            返回Callable中call方法的返回值,该方法让程序最多阻塞timeout毫秒的时间,或者直到unit时间
            点。如果在指定的时间Callable的任务没有完成就会抛出异常TimeoutEexception
    (4).   boolean  isCancelled()    
            如果Callable中的任务被取消,则返回true,否则返回false
    (5).    boolean isDone()
            如果Callable中的任务被完成,则返回true,否则返回false

代码演示说明:
1.  通过继承Thread类创建线程
public class MyThread extends Thread {
	private int count ;	//每个新进程类都有独立的成员变量count
	@Override
	public void run() {  //重写run方法
		for (count = 1; count <= 5; count++) {
			System.out.println(getName() + " :" + count);
		}
	}

	public static void main(String[] agrs) {
		for (int j = 1; j <= 10; j++) {
			System.out.println(Thread.currentThread().getName()+" :"+j);
			if(j == 5){
				new MyThread().start(); 
				new MyThread().start();  //俩个子线程和主线程并发执行
			}
		}
	}
}
执行结果:(输出结果不唯一)每个子线程都输出5次,主线程输出10次,因子进程通过继承Thread类创建,拥有自己独立的成员变量count=5;
main :1
main :2
main :3
main :4
main :5
main :6
Thread-0 :1
main :7
main :8
main :9
main :10
Thread-1 :1
Thread-0 :2
Thread-0 :3
Thread-0 :4
Thread-1 :2
Thread-0 :5
Thread-1 :3
Thread-1 :4
Thread-1 :5


2.  通过实现Runnable接口来创建线程

public class NewThread implements Runnable {
	private int count;  //用同一个NewThread类开辟的不同线程共享同一个类的成员变量
	@Override
	public void run() {
			for(count = 1; count < 5; count++){
				System.out.println(Thread.currentThread().getName() + " :" + count);
			} //利用Thread.currentThread()获得当前进程
	}
	public static void main(String[] agrs){
		NewThread nt = new NewThread();
		for (int j = 1; j <= 10; j++) {
			System.out.println(Thread.currentThread().getName()+" :"+j);
			if(j == 5){
				new Thread(nt).start(); 
				new	Thread(nt).start();  //俩个子线程和主线程并发执行
			}
		}
	}
}
执行结果:(输出结果不唯一),通过同一个实现Runnable接口的类创建多个子线程共享该类的成员变量count = 5,所以两个子线程Thread-0 和Thread-1一共输出5次,主线程输出10次。
main :1
main :2
main :3
main :4
main :5
main :6
main :7
Thread-0 :1
main :8
Thread-1 :1
main :9
Thread-0 :2
main :10
Thread-1 :2
Thread-0 :3
Thread-1 :4


3.通过实现Callable接口利用TaskFutrue来创建线程

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class CallableThread implements Callable<String> {
	private boolean flag;
	public CallableThread(boolean f) {
		this.flag = f;
	}
	@Override
	public String call() throws Exception {
		for (int i = 1; i <= 5; i++) { 
			//执行输出5次,因为call方式是阻塞方式的,所以这五次输出应该是连续
			System.out.println(Thread.currentThread().getName() + " :" + i);
		}
		return flag == true ? "flag is true" : "flag is false";
	}
}
public class FutureThread {
	public static void main(String[] agrs) {
		CallableThread ct1 = new CallableThread(false);
		CallableThread ct2 = new CallableThread(true);
		CallableThread ct3 = new CallableThread(false);
		FutureTask<String> task1 = new FutureTask<String>(ct1);
		FutureTask<String> task2 = new FutureTask<String>(ct2);
		FutureTask<String> task3 = new FutureTask<String>(ct3);
		Thread thread1 = new Thread(task1);  //创建第一个线程
		Thread thread2 = new Thread(task2); //创建第二个线程
		Thread thread3 = new Thread(task3); //创建第三个线程
		for(int i = 1; i <= 10; i++){
			System.out.println(Thread.currentThread().getName()+"  :"+i);
			if(i == 5){
				try{
					thread1.start();	//启动第一个线程
					System.out.println("task1 get value: "+task1.get());
					thread2.start();	//启动第二个线程
					System.out.println("task2 get value: "+task2.get());
					thread3.start();   //启动第三个线程
					System.out.println("task3 get value: "+task3.get());
				}catch(Exception e){
					e.printStackTrace();
				}//每个线程的task调用get方法的时候都会阻塞程序,所以会连续输出5次后执行后面的程序
			}
		}
	}
}
执行结果:(可能不唯一,但是Thread-0 :1到task3 get value: flag is false之间的输出是相同的,具体原因就是FutureTask的get()方法会使程序阻塞)
<span style="font-size:18px;">main  :1
main  :2
main  :3
main  :4
main  :5
Thread-0 :1
Thread-0 :2
Thread-0 :3
Thread-0 :4
Thread-0 :5
task1 get value: flag is false
Thread-1 :1
Thread-1 :2
Thread-1 :3
Thread-1 :4
Thread-1 :5
task2 get value: flag is true
Thread-2 :1
Thread-2 :2
Thread-2 :3
Thread-2 :4
Thread-2 :5
task3 get value: flag is false
main  :6
main  :7
main  :8
main  :9
main  :10</span>

对于Callable配合ExecutorService使用创建线程请参考我的下一篇博文,实现的效果跟Callable配合FutureTask的效果大体相同。












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值