一、三种方法的编程实现
1.Thread
public class Thread创建线程 {
/**
*
* <p>Description: 非静态内部类中默认持有外部类的引用.
* 优点:编程简单,无需通过Thread.currentThread()获取当前线程,通过this即可获取
* 缺点:不能再继承其他类</p>
* @author 杨丽金
* @date 2018-4-16
* @version 1.0
*/
static class MyThread extends Thread{
public void run(){
for(int i=0;i<100;i++){
System.out.println(this.getName()+":"+i);
}
}
}
public static void main(String[] args) {
for(int i=0;i<100;i++){
if(i==20){
new MyThread().start();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
2.Runnable
public class Runnable创建线程 {
/**
*
* <p>Description: Runnable创建线程
* 优点:1)可以继承别的类
* 2)多个线程可以共享target对象,非常适合多个线程共享同一份资源的情况
* 缺点:获取当前要线程要通过Thread.currentThread()方法
* </p>
* @author 杨丽金
* @date 2018-4-16
* @version 1.0
*/
static class MyRunnable implements Runnable{
// 变量会被创建的多个线程共享,存在线程同步问题
volatile int i=0;
public void run(){
// 方法中的局部变量是线程私有的,是线程安全的
for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public static void main(String[] args) {
/*for(int i=0;i<100;i++){
if(i==20){
new Thread(new MyRunnable()).start();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}*/
// 演示两个子线程线程共享变量的例子
Runnable r=new MyRunnable();
new Thread(r,"子线程1").start();
new Thread(r,"子线程2").start();
}
}
3.Callable
/**
*
* <p>Description:
* 优点:1)可以继承别的类
* 2)多个线程可以共享target对象,非常适合多个线程共享同一份资源的情况
* 缺点:获取当前要线程要通过Thread.currentThread()方法</p>
* @author 杨丽金
* @date 2018-4-16
* @version 1.0
*/
public class Callable创建线程 {
public static void main(String[] args) {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==20){
// 开启线程
/*
* Callable接口不是Runnable接口的子接口,故不可作为Thread的target传入
* Callable是泛型接口,使用时需要指定泛型
*/
Callable<Integer> ca=new MyCallable();
/*
* 此处是泛型的菱形语法
* Future接口,JAVA提供了它的一个实现类FutureTask(实现了Future接口和Runnable接口),可以作为Thread的target传入
*/
FutureTask<Integer> ft=new FutureTask<>(ca);
Thread t=new Thread(ft);
t.start();
try {
/*
* 调用get()方法后主线程会被阻塞,等待子线程返回结果
*/
System.out.println("线程返回结果"+ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
static class MyCallable implements Callable<Integer>{
// 该变量可被多个线程共享
int i=0;
/**
* call()方法是线程执行体
* 1)可以有返回值,泛型指定
* 2)可以声明抛出的异常
*/
@Override
public Integer call() throws Exception {
for(i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
return i;
}
}
}
二、方法的优缺点对比
- 通过继承Thread类创建线程:
- 优:编程简单。可通过
this
关键字直接获得当前线程 - 缺:单继承多接口
- 通过实现接口创建线程:
- 优:1)适合多个线程共享同一份资源的情况;2)单继承多接口
- 缺:编程复杂。需要通过
Thread.currentThread()
获取当前线程
通过实现Callable
接口(这是一个泛型接口,在其实现类中要指定具体的泛型类型):1)线程执行体可指定返回值,2)并且可声明异常【可不声明】
通过实现Runnable
接口:无上述特性