创建线程的3种方式
Java线程状态变迁图
构造一个线程
在线程执行start()
方法之前,首先需要初始化(NEW)一个线程,初始化的时候,可以设置线程名称,线程所属的线程组、线程优先级、是否是Daemon线程等信息。
Thread常见参数及设置方法:
//线程是否是守护线程 默认false private boolean daemon = false; //设置方法 Thread thread=new Thread(); thread.setDaemon(true);
//线程名字 默认"Thread-" + nextThreadNum() private volatile String name; //设置方法 Thread thread=new Thread(); thread.setName("myThread"); //不能设置为null,会报异常
//线程优先级 是否起作用和操作系统及虚拟机版本相关 private int priority; //设置方法 范围:1-10 默认5 myThread.setPriority(1);
Thread源码构造方法
在Thread源码中,一共提供了9种
构造方法.
从这些构造方法中,大致可以分为有Runnable构造参数
的,和无Runnable构造参数
两大类,无Runnable构造参数的就需要去继承Thread
来重写run()
方法(注:Thread
也实现了Runnable接口),有Runnable构造参数的,就实现Runnable接口的run方法,然后通过构造参数,把实现Runnable接口的实例传入Thread.
无返回值的线程
可以看到,通过集成Thread
类和实现Runnable
接口的run()
方法返回值都是void
.这类是没有返回值的
方法一:继承Thread类创建一个线程
//继承Thread类,重写run方法
class MyThread extends Thread{
@Override
public void run() {
System.out.println("继承Thread,重写run方法");
}
}
public class ThreadTest{
public static void main(String[] args){
MyThread myThread=new MyThread();
myThread.start();
}
}
方法二:实现Runnable接口创建线程
//实现Runnable接口的run方法,然后以构造参数的形式设置Thread的target
class MyRun implements Runnable{
@Override
public void run() {
System.out.println("实现Runnable方法");
}
}
public class ThreadTest{
public static void main(String[] args){
MyRun myRun=new MyRun();
Thread thread=new Thread(myRun);
thread.start();
}
}
有返回值的线程
上面两个方法,都有一个共同缺点,就是没有返回值,当有一些特殊需求时,比如开启一个线程,用来计算一些东西,或者是处理另外一些需要返回数据的业务,这时就需要借助FutureTask
来完成了
方法三:通过FutureTask创建一个线程
//实现Callable接口的call方法 类似实现Runnable的run方法
class MyCall implements Callable<Integer>{
@Override
public Integer call() throws Exception {
//计算1+1
return 1+1;
}
}
public class ThreadTest{
public static void main(String[] args){
MyCall myCall=new MyCall();
//创建异步任务
FutureTask<Integer> futureTask=new FutureTask<>(myCall);
Thread thread2=new Thread(futureTask);
thread2.start();
//获取线程执行结果
Integer res=futureTask.get();
System.out.println(res); //输出2
}
}
总结
使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过set方法设置参数或者通过构造函数进行传递,而如果使用Runnable方式,则只能使用主线程里面被声明为final的变量。不好的地方是Java不支持多继承,如果继承了Thread类,那么子类不能再继承其他类,而Runable则没有这个限制。前两种方式都没办法拿到任务的返回结果,但是Futuretask方式可以。