1.线程创建
- 通过继承Thread类来创建线程,在执行时new MyThread() .start()
- 通过实现Runnable接口来创建线程,在执行时 MyThread mt=new MyThread(); new Thread(mt).start();
- 通过ExecutorService和Callable<Class>实现有返回值的线程
- 基于线程池
Thread和Runnabel区别:
(1)Runnable接口的实例是Thread的target,里面的run方法只是个方法体,而真正的线程对象依旧是Thread的实例,调用target的run方法。其实通过jdk文档可以明白很多,Thread类本身就已经实现了Runnable接口的,而通过实现Runnable接口创建的线程实际上是一个Runnable target作为Thread类的输入参数。new Thread(Runnable target),这里的Thread对象的start方法为该线程创建执行初始化操作,然后调用了Runnable里的run方法。
(2)通过继承Thread类来创建的线程不共享实例变量,通过实现Runnable接口来创建的线程对象共享线程类的实例变量。如:例子中的变量i, 对于方法一输出的两个线程的 I 是不连续的 无关的;而方法二中的线程1和线程2,在i上的操作是连续的。 这是因为Runnable接口实现的只是Thread类的target,多个线程共享一个target,所以就共享其实例变量。
(3)Thread来创建线程类在调用当前线程的相关方法时可直接执行方法,而Runnable接口创建的线程类要通过Thread.currentThread()静态方法先获取当前线程,再调用其他方法。
(4)从Java8开始,Runnable接口使用了@FunctionalInterface修饰,支持函数式编程,Callabel接口也是支持函数式编程的。
(5)使用Thread类创建线程的局限就是不支持多继承,因为Java是单继承机制,所以为了多继承会通过实现Runnable接口来创建线程。
3.其他
start方法看起来执行了一个长期的方法调用,其实不是的,它很快就返回了,只是该方法调用的实际上是run方法的引用,并且这个方法还没执行结束呢,而这是另外一个线程执行的,所以run其实是和main同时运行,见下图。
Runnable导出一个类时,它的run只是一个方法而已,并不会有任何内在的线程能力,他必须显示的将任务附着在一个线程上。
多次调用start会出现IllegalThreadStateException异常;
start方法实际是将线程进入就绪状态,等待cpu执行run方法,如果直接调用thread.run方法,那么就和普通方法没差,不是异步操作,而是有main主线程调用一个方法而已。
/**
* @Title: MyThread.java
* @Package thread
* @Description: TODO(用一句话描述该文件做什么)
* @author LingLee
* @date 2017年3月21日 下午2:47:33
* @version V1.0
*/
package thread;
/**
* @Title: MyThread
* @Description:
*/
class FirstThread extends Thread {
private int i;//不共享实例变量
public void run(){
for(;i<100;i++){
System.out.println(getName()+"\t"+i);
}
}
}
class SecondThread implements Runnable{
private int i;//共享实例变量
public void run(){
for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
}
}
public class MyThread {
public static void main(String[] args){
for(int i=0;i<50;i++ ){
System.out.println(Thread.currentThread().getName()+"\t"+i);
if(i==20){
// new FirstThread().start();
// new FirstThread().start();
SecondThread st=new SecondThread();
new Thread(st,"线程1").start();//真正的线程对象依然是Thread的实例,=
new Thread(st,"线程2").start();//runnable只是thread类的target
}
}
}
}
4引申:一个类可以即继承Thread同时实现Runnable
例子
public class Test extends Thread implements Runnable{
public static void main(String[] args){
Thread t=new Thread(new Test());
t.start();
}
/*
Test没有实现Runnable中的run方法,是因为从Thread类中继承了run,这个run可以当做
Runnable接口的实现。所以这段代码能够编译通过
*/
}
public class Test extends Thread implements Runnable{
public void run(){
System.out.println("this is run");
}
public static void main(String[] args){
Thread t=new Thread(new Test());
t.start();
}
/*
Test实现Runnable中的run方法,运行结果为this is run
*/
}