所有的线程对象必须是Thread类或者其子类的实例。
1.继承Thread类
(1)定义Thread类的子类,重写thread类里的run方法
(2)创建thread子类的实例,即创建线程对象
(3)调用线程对象的start()方法
public class firstThread extends Thread
{
private int i;
//重写run方法
public void run(){
for( ;i<100;i++)
{
System.out.println(getName()+i);
}
}
public static void main(String[] args)
{
for(int i=0;i<100;i++){
//Thread.currentThread()获取当前线程
System.out.println(Thread.currentThread().getName()+i);
if(i==20)
{
//创建并启动第一个线程
new firstThread().start();
//创建并启动第二个线程
new firstThread().start();
}
}
}
}
上边包含了两个方法
Thread.currentThread():是 Thread类的静态方法,返回当前正在执行的线程对象。
getName():是 Thread类的实例方法,返回调用该方法的线程名字。
2.实现Runnable接口创建线程类
(1)定义Runnable接口的实现类,并重写run()方法,该方法仍是线程执行的执行体。
(2)创建Runnable实现类的实例,并把这个实例当做Thread的target来创建Thread对象,这个Thread才是真正的线程对象。
(3)调用线程对象的start()方法启动线程。
Runnable对象(Runnable实现类的实例)仅仅作为Thread对象的target,而实际的线程对象仍然是Thread实例,只是该Thread线程负责执行其target里的run()方法。
public class secondThread implements Runnable
{
private int i;
//重写run方法
public void run(){
for( ;i<100;i++)
{
System.out.println(Thread.currentThread.getName()+i);
//当线程类实现runnable接口时,只能用thread.currentThread()方法获取当前线程对象。
}
}
public static void main(String[] args)
{
for(int i=0;i<100;i++){
//Thread.currentThread()获取当前线程
System.out.println(Thread.currentThread().getName()+i);
if(i==20)
{
secondThread s=new secondThread();
//通过new Thread(target,name)方法创建线程
new Thread(s,"线程1").start();
new Thread(s,"线程2").start();
}
}
}
}
3.使用Callable和Future创建线程
Callable接口提供了一个call()方法作为线程执行体,call()方法要比run()方法功能强大。
(1)call()方法可以有返回值。
(2)call()方法可以声明抛出异常
Callable接口并不是Runnable接口的子接口,所以其不能直接作为Thread类的target。而且call()方法有一个返回值。要考虑如何获取call()方法的返回值。
java5 提供了Future接口来代表Callable接口里的call()方法的返回值。并为Future接口提供了一个FutureTask实现类。该实现类既实现了Future接口也实现了Runnable接口。---即可以作为FutureTask实现类可以作为Thread类的target。
Future接口定义了几个方法来控制其关联的Callable任务。
(1)boolean cabcel(boolean may) 试图取消该Future里关联的Callable任务。
(2)V get() 返回Callable任务里call()方法的返回值。调用该方法将导致程序阻塞,必须等到子线程结束后才会得到返回值。
(3)boolean isCancelled() 如果在Callable任务正常完成前被取消,则返回true;
(4)boolean isDone() 如果Callable任务已完成,则返回true;
Callable接口有泛型限制,其泛型形参类型与call()方法返回值类型相同。
Callable接口是函数式接口(只有一个抽象方法),故可使用Lambda表达式创建Callable对象。
线程启动步骤:
(1)创建Callable接口实现类,并实现call()方法,在创建Callable接口实现类的实例,以上可直接用Lambda表达式一步到位。
(2)用FutureTask类包装Callable实现类对象,该FutureTask对象包装了call()方法中的返回值。
(3)用FutureTask对象作为Thread对象的target来创建并且启动线程。
(4)可用FutureTask对象的get()方法来获得子线程执行结束后的返回值(即call方法的返回值)
代码示例
public class thirdThread
{
public static void main(String[] args)
{
FutureTask<Integer> task=new FutureTask<>((Callable<Integer>)()->{
//call()方法的方法体
int i=0;
for( ;i<100;i++)
{
System.out.println(Thread.currentThread.getName()+i);
}
//返回i
return i;
})
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
if(i==20)
{
new Thread(task,"有返回值的线程").start();
}
}
}
}