Thread 类构造方法的研究
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,long stackSize) {
init(group, target, name, stackSize);
}
//Thread类的每个构造方法都调用了init方法,Thread共有8个构造方法
//而且所有的构造方法都依赖于init方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
Thread类的部分方法:
通过Thread的函数声明和方法我们知道Thread类是继承了一个叫Runnable的接口,并实现了这个接口的run方法
并且只能通过Thread类对象调用start()方法来启动一个新线程
从init的参数方法签名来看,构造一个Thread最多需要五个值,也就是说对于一个基本的Thread,能够运行的Thread,最大集合为五个;
但是通过构造方法可以看得出来,全部都是调用的四个版本的init方法,都没有传递AccessControlContext acc,在五个参数的版本中有设置默认值。
所以目前(1.8)支持Thread运行的构造参数最大集合个数为四,他们分别是:
ThreadGroup g
Runnable target
String name
long stackSize
最重要的是target参数,targer对象是实现了Runnable接口的类对象,这个参数指向的是你封装的任务在哪。
没有这个参数,就启动不了你指定的任务
任务的封装有多种,所以创建Thread类对象的时候指向你封装的任务就能启动对应的任务
Thread()空参构造方法和Thread(String name)创建的对象的target指向的是本对象的run()方法
Thread(含有Runnable target的参数)这样的构造方法重新定向了targer对象指定的任务,这样target指向
的任务就变成了实现Runnable的类的run()方法。
所以启动一个新的线程,要看targer的目标,targer指向的是这个新线程的任务(封装run方法的对象)
第一种方法是继承Thread类,创建本类对象来启动新线程。继承Thread类的子类的targer变量指向的是本类对象的run方法,
第二种方法是一个类实现Runnable接口来封装任务,利用Thread类的构造方法Thread(Runnable targer)来创建新的(Thread类对象)线程对象
因为Runnable接口有子接口,和具体的实现类所以也可以把Runnable的具体实现类传递给targer参数。
如FutureTask类,这个实现类有点特殊,因为他不仅实现了Runnable接口,而且还实现了一个叫Callable的接口
所以利用这个类,可以封装一种可抛异常可有返回值的任务。这个任务就封装在Call()方法中。所以这种方法的本质还是
属于第二种方法,因为传递给targer的参数还是实现了Runnable接口的类的对象
第一种方法
public class TheFristWay extends Thread {
public TheFristWay(){}
public TheFristWay(String name){
super(name);
}
public static void main(String[] args) {
TheFristWay t = new TheFristWay("继承Thread的线程"); //继承Thread类来创建一个线程的时候,如果不重写构造方法,只能使用空参构造,因为Thread的构造方法不能被继承
t.start();
System.out.println("main is running ");
}
public void run(){ //run只是用来封装任务,具体的执行需要start调用
System.out.println(Thread.currentThread().getName()+" is running");
}
}
第二种方法:1:
public class TheSecondWay {
public static void main(String[] args) {
//new Thread 是用来调用start方法的,new TheThread 是实现Runnable接口的对象
new Thread(new TheThread(),"继承Runnable封装的线程").start();
System.out.println("main is running ...");
}
}
//这个类实现了Runnable并重新封装了run任务
class TheThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" is running...");
}
}
第二种方法:2:
public class TheThiredWay {
public static void main(String[] args) throws Exception {
//Runnable接口的具体实现类(FutureTask对象),利用实现了Callable接口的对象来构造对象
FutureTask f = new FutureTask<>(new TheThred2());
//Thread类对象利用Runnable具体实现类来启动新线程
new Thread(f).start();
//用FutureTask对象来获取返回值
String s = f.get();
System.out.println(s);
}
}
class TheThred2 implements Callable{
@Override
public String call() throws Exception {
System.out.println("这是call方法中封装的任务语句执行的结果");
System.out.println(Thread.currentThread().getName());
return "这是FutureTask对象通过get方法来获取的返回值"; //返回值,可以用FutureTask的get方法获取
}
}
当使用 runnable 接口时,您不能直接创建所需类的对象并运行它;必须从 Thread 类的一个实例内部运行它。
实现Runnable接口创建线程比继承Thread类创建线程所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立