目录
继承Thread类
实现Runnable接口
通过Callable和Future创建对象
继承Thread类
- 定义Thread类的子类,并重写run()方法
- 创建该子类的实例,即创建了线程对象
- 调用线程对象的start()方法类启动该线程
package com.cn.thread;
/**
* 1.定义Thread类的子类,并重写run()方法
*/
public class ThreadDemoOne extends Thread {
@Override
public void run() {
System.out.println("启动线程。。。");
}
public static void main(String[] args) {
// 2.创建该子类的实例,即创建了线程对象
ThreadDemoOne threadDemoOne = new ThreadDemoOne();
// 3.调用线程对象的start()方法类启动该线程
threadDemoOne.start();
}
}
实现Runnable接口
- 定义了一个实现Runnable接口的类,并重写run()方法
- 创建该类的实例,并将此实例作为Thread类的target来创建Thread对象,该Thread对象是真正的线程对象
- 调用该线程对象的start()方法启动该线程
package com.cn.thread;
/**
* 1.定义了一个实现Runnable接口的类,并重写run()方法
*/
public class ThreadDemoTwo implements Runnable {
public void run() {
System.out.println("启动线程。。。");
}
public static void main(String[] args) {
// 2.创建该类的实例,并将此实例作为Thread类的target来创建Thread对象,该Thread对象是真正的线程对象
ThreadDemoTwo threadDemoTwo = new ThreadDemoTwo();
Thread thread = new Thread(threadDemoTwo);
// 3.调用该线程对象的start()方法启动该线程
thread.start();
}
}
通过Callable和Future创建对象
- 定义一个实现Callable接口的类,并实现call()方法,该call方法将作为线程执行体,并且有返回值
- 创建该类的实例
- 创建FutureTask的实例,即使用FutrueTask类来包装Callable对象
- 将FutureTask的实例作为Thread的target创建并启动新线程
- 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
package com.cn.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 1.定义一个实现Callable接口的类,并实现call()方法,该call方法将作为线程执行体,并且有返回值
*/
public class ThreadDemoThree implements Callable<Integer> {
public Integer call() {
int sum = 0;
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
sum += i;
}
return sum;
}
public static void main(String[] args) {
// 2.创建ThreadDemoThree对象
Callable<Integer> myCallable = new ThreadDemoThree();
// 3.创建FutureTask的实例,即使用FutrueTask类来包装Callable对象
FutureTask<Integer> ft = new FutureTask<Integer>(myCallable);
// 4.将FutureTask的实例作为Thread的target创建并启动新线程
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
Thread thread = new Thread(ft); //FutureTask对象作为Thread对象的target创建新的线程
thread.start(); //线程进入到就绪状态
}
}
System.out.println("主线程for循环执行完毕..");
// 5.调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
try {
int sum = ft.get(); //取得新创建的新线程中的call()方法返回的结果
System.out.println("sum = " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target。那么看下FutureTask类的定义:
public class FutureTask<V> implements RunnableFuture<V> {
//....
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
于是,我们发现FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。
执行下此程序,我们发现sum = 4950永远都是最后输出的。而“主线程for循环执行完毕..”则很可能是在子线程循环中间输出。由CPU的线程调度机制,我们知道,“主线程for循环执行完毕..”的输出时机是没有任何问题的,那么为什么sum =4950会永远最后输出呢?
原因在于通过ft.get()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ft.get()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。
上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)