在java平台中创建线程就是创建一个Thread类或者其子类的实例。每个线程的任务处理逻辑都在run()方法中实现,它在java虚拟机中由相应的线程直接调用。
运行一个线程就是让java虚拟机执行该线程的run()方法。
启动线程需要调用Thread类的strat()方法。
下面代码实现创建线程.
继承Thread类
public class ThreadApp01 { public static void main(String[] args) { Thread myThread = new MyThread(); myThread.start(); } } class MyThread extends Thread { @Override public void run() { System.out.println("继承Thread类"); } } }
实现Runable接口
public class ThreadApp02 { public static void main(String[] args) { Thread myThread2 = new Thread(new MyThread2()); myThread2.start(); } } class MyThread2 implements Runnable{ @Override public void run() { System.out.println("实现Runable接口"); } }
通过Callable和FutureTask创建线程
a. 创建Callable接口的实现类,并实现call()方法;
b. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callback对象的call()方法的返回值;
c. 使用FutureTask对象作为Thread对象的target创建并启动新线程;
d. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
public class CallableThreadTest implements Callable<Integer> { public static void main(String[] args) { CallableThreadTest ctt = new CallableThreadTest(); FutureTask<Integer> ft = new FutureTask<Integer>(ctt); // Thread thread = new Thread(ft,"有返回值的线程"); // thread.start(); for(int i = 0;i < 100;i++) { System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i); if(i==20) { new Thread(ft,"有返回值的线程").start(); } } try { System.out.println("子线程的返回值:"+ft.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } @Override public Integer call() throws Exception { int i = 0; for(;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } return i; } }
不管是哪种方式,当该线程的run方法执行时,线程就结束,所占的资源会被垃圾回收器回收。我们不能通过start方法再一次调用,否则会抛出IllegalThreadExcepton异常.
一个线程就是一个对象,创建时会为其分配内存空间,JAVA平台的线程还会为其创建一个内核线程,相对来说成本较高。
三种创建方式的区别:
第二种和第三种基本很类似,只是实现callable可以有返回值。
从面向对象编程角度:第一种是一种基于继承(Inheritance)的技术。第二,三种是一种基于(Composition)的技术,由于组合相对继承来说,类与类之间的耦合程度较低,更灵活.
从对象共享的角度:第二种方式可能导致多个线程实例共享一个Runable实例,可能涉及一些线程安全方面的因素.
从对象创建成本 : 创建一个线程实例比创建一个Runable实例成本相对来说高.