1、方法 1: 覆盖Thread类的run方法,Thread类本身 implements Runnable;如下演示代码:
package com.tiger.practice;
/**
* 方法 1: 覆盖Thread类的run方法,Thread类本身 implements Runnable
* 优点:1、编程难度低
* 2、直接继承Thread 复写run方法
* 3、直接可以start
* 4、可以方便获取线程属性,name[getName();],线程id[getId();]
*
* 缺点:局限性-->不能再继承其他类
* @author tiger
* @Date 2017年7月24日
*/
public class FirstThreadDemo extends Thread{
public static void main(String[] args) throws Throwable {
/*--------------------子线程 start--------------------*/
MyThread1 th1 = new MyThread1();
th1.start();
MyThread2 task = new MyThread2();//创建任务体
Thread th2 = new Thread(task);
Thread th3 = new Thread(task);
th2.start();
th3.start();
//开启使用线程
task.start();
/*--------------------子线程 end--------------------*/
/*--------------------主线程 start--------------------*/
for (int i = 0; i < 20; i++) {
System.out.println("主线程 - 执行第[" + i+"]次");
Thread.sleep(10);
}
/*--------------------主线程 end--------------------*/
}
}
/**
* 局限性 : 不能再继承其他类
* @author tiger
* @Date 2017年7月24日
*/
class MyThread1 extends Thread{//局限性不能再继承其他类
//复写run方法,是一个任务执行体,调用start方法,会自动调用run,会自动启动线程。
public MyThread1(String name) {
super(name);
}
public MyThread1() { }
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(getName()+ " 执行第[" + i+"]次");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 测试两个线程共用一个任务体。
* @author tiger
* @Date 2017年7月24日
*/
class MyThread2 extends Thread{//局限性不能再继承其他类
int num;
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("Thread-1 执行第[" + i+"]次");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2、方法 2 :任务执行体 implements Runnable;如下演示代码:
package com.tiger.practice;
/**
* 方法 2 :任务执行体 implements Runnable
*
* 优点:1、如果只是定义任务执行体,就选用Runnable这种。
*
* 缺点:1、获取线程的属性不方便。
* @author tiger
* @Date 2017年7月24日
*/
public class TwoThreadDemo extends Thread{
public TwoThreadDemo(Runnable runnable) {
super( runnable );
}
public TwoThreadDemo() { }
public static void main(String[] args) throws Throwable {
/*--------------------子线程 start--------------------*/
TwoThreadDemo th1 = new TwoThreadDemo(new Task());
th1.start();
//创建 2 个线程共用一个任务体(共享同一份资源)task2 ?
Task2 task2 = new Task2();
Thread th2 = new Thread(task2);
Thread th3 = new Thread(task2);
th2.start();
th3.start();
/*--------------------子线程 end--------------------*/
/*--------------------主线程 start--------------------*/
for (int i = 0; i < 10; i++) {
System.out.println("主线程 - 执行第[" + i+"]次");
Thread.sleep(20);
}
/*--------------------主线程 end--------------------*/
}
}
/**
* 定义一个任务执行体
* @author tiger
* @Date 2017年7月24日
*/
class Task implements Runnable{
//覆盖run方法
@Override
public void run() {
//在任务体中获取当前线程属性
Thread thread = Thread.currentThread();
try {
for (int i = 0; i < 10; i++) {
System.out.println("子线程 1 执行第[" + i+"]次" + thread.getName());
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 定义另一个任务执行体
* @author tiger
* @Date 2017年7月24日
*/
class Task2 implements Runnable{
//覆盖run方法
@Override
public void run() {
Thread thread = Thread.currentThread();
try {
for (int i = 0; i < 10; i++) {
System.out.println("子线程 2 执行第[" + i+"]次"+ thread.getName());
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3、方法 3 :任务执行体 implements Callable,是为了获取线程返回值而设计;只有在需要获取返回值时才用次方法。如下演示代码:
package com.tiger.practice;
import java.util.concurrent.*;
/**
* 方法 3 :任务执行体 implements Callable,是为了获取线程返回值而设计。
* 只有在需要获取返回值时才用次方法。
*
* 优点:1、是一个增强型的任务体。
* 2、可以获取线程的返回值。
* 3、可以终止任务的执行。
* 4、探知线程执行情况。
*
* 缺点:1、变成较为复杂。
* @author tiger
* @Date 2017年7月24日
*/
public class ThreeThreadDemo {
public static void main(String[] args) throws InterruptedException {
/*--------------------子线程 start--------------------*/
// MyTask task = new MyTask();
FutureTask<Integer> ft = new FutureTask<Integer>( new MyTask());
Thread th = new Thread(ft,"线程1");
th.start();
/*--------------------子线程 end----------------------*/
/*--------------------主线程 start----------------------*/
for( int i=1; i<=50; i++ ){
System.out.println("主线程 - 执行第[" + i+"]次");
Thread.sleep( 3 );
}
try {
//主线程阻塞在此, 等那一个线程执行完
// System.out.println("sum = "+ft.get());
// 等那一个线程,如果等了 1 ms 还未返回结果,则终止等待。防止线程堵塞。
System.out.println( "sum = "+ ft.get( 1, TimeUnit.SECONDS ));
//终止取消任务执行
boolean cancel = ft.cancel(true);
//获取执行状态
boolean ret = ft.isDone();
while (!ret){
ret = ft.isDone();
System.out.println("子线程运行状态 : "+ret);
Thread.sleep( 15 );
}
System.out.println("cancel : "+cancel);
System.out.println("探测子线程是否完成 : "+ret);
}catch (InterruptedException e) {//被打断异常
e.printStackTrace();
} catch (ExecutionException e) {//被执行异常
e.printStackTrace();
}
catch (TimeoutException e) {
System.out.println( "主线程中 获取返回值超时." );
}
/*--------------------主线程 end----------------------*/
}
}
/**
* 定义一个任务执行体 implements Callable
* @author tiger
* @Date 2017年7月24日
*/
class MyTask implements Callable <Integer> {
//重写call方法
@Override
public Integer call() throws Exception {
Integer sum = 0;
for( int i=1; i<=50; i++ ){
sum += i;
System.out.println("子线程 1 执行第[" + i+"]次");
Thread.sleep( 20 );
}
return sum;
}
}
以上几种创建方式各有特点,见代码注释。