Java中如何创建一个线程?

一、创建线程的三种方式

1.继承Thread类创建线程类

  1. 定义Thread类的子类,并重写该类的run(),该run()的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
  2. 创建Thread()子类的实例,即创建了线程对象
  3. 调用线程对象的start()方法来启动该线程
public class ThreadDemo01 extends Thread{
	public ThreadDemo01(){
		// 构造方法
	}
	public void run(){
		//编写自己的线程代码
		System.out.println(Thread.currentThread().getName());
	}
	public static void main(String[]args){
		ThreadDemo01 threadDemo01 = new ThreadDemo01();
		threadDemo01.setName("我是自定义的线程1");
		threadDemo01.start();
		System.out.println(Thread.currentThread().toString());
	}
}

程序结果:
Thread[main,5,main]
我是自定义的线程1

2.通过Runnable接口创建线程类

  1. 定义Runnable接口的实现类,并重写接口的run()方法,该方法的方法体同样是线程的线程执行体
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程
  3. 调用线程对象的start()方法来启动该线程
public class ThreadDemo02{
	public static void main(String[]args){
		System.out.println(Thread.currentThread().getName());
		Thread t1 = new Thread(new MyThread());
		t1.start();
	}
}
class MyThread implements Runnable{
	@Override
	public void run(){
		Sysytem.out.println(Thread.currentThread.getName()+"-->我是通过实现接口的线程方式");
	}
}

程序运行结果:
main
Thread-0->我是通过实现接口的线程实现方式!

3.通过Callable和Future创建线程

  1. 创建Callable接口的实现类,并实现call()方法,该call()方法作为线程执行体,并且有返回值。
  2. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
    FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了Future和Runnable接口。
  3. 使用FutureTask对象作为Thread对象的target创建并启动新线程
  4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
public class ThreadDemo03{
	public static void main(String[]args){
		Callable<Object> oneCallable = new Tickets<Object>();
		FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);
		Thread t = new Thread(oneTask);
		System.out.println(Thread.currentThread().getName());
		t.start();
	}
}
class Ticket<Object> implements Callable<Object>{
	@Override
	public Object call()throws Exception{
		System.out.println(Thread.currentThread().getName()+"->我是通过实现Callable接口通过FutureTask包装器来实现的线程");
		return null;
	}
}

程序运行结果:
main
Thread-0->我是通过实现实现Callable接口通过FutureTask包装器实现的线程

前面两种可以归结为一类:没有返回值,通过重写run(),run()的返回值是void,所以没有办法返回结果。
后面两种可以归结为一类:有返回值,通过Callable接口,就要实现call(),这个方法的返回值是Object,所以返回的结果可以放在Object对象中。

4.通过线程池创建线程

public class ThreadDemo05{
	private static int POOL_NUM = 10;//线程池数量
	public static void main(String[]args) throw InterruptedException{
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		for(int i = 0;i<POOL_NUM;i++){
			RunnaleThread threa = new RunnableThread();
			executorService.execute(thread);
		}
		//关闭线程池
		executorService.shutdowm();
	}
}
class RunnableThread implements Runnable{
	public void run(){
		System.out.println("通过线程池方式创建的线程:"+Thread.currentThread().getName()+" ");
	}
}

二、创建线程的三种方式的对比

1.采用实现Runnable、Callable接口的方式创建多线程

优点:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现面向对象的思想。
劣势:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

2.使用继承Thread的方式创建多线程

优势:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程
劣势:
线程类已经继承了Thread类,所以不能再继承其他父类。

3.Runnable和Callable的区别

  1. Callable接口重写的方法是call(),Runnable重写的方法是run()
  2. Callable的任务执行后可返回值,Runnable的任务执行不可返回值
  3. call方法可以抛出异常,run方法不可以
  4. 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

版权声明:本文为weixin_46248981原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。