Java创建线程的方式有哪些?相互之间有什么不同?

1.继承Thread类
定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务(执行体)。
创建Thread子类的实例,即创建了线程对象,调用线程对象的start()方法来启动该线程。

public class ThreadTest extends Thread {

	int i = 0;

	// 重写run方法,run方法的方法体就是现场执行体
	public void run() {
		for (; i < 100; i++) {
			System.out.println(getName() + "  " + i);
		}
	}

	public static void main(String[] args) {

		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "  : " + i);
			if (i == 50) {
				new ThreadTest().start();
				new ThreadTest().start();
			}
		}
	}

}

2.实现Runnable接口
重写该接口的run()方法,创建Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象,调用线程对象的start()方法来启动该线程。
用于自己的类已经extends另一个类(此时无法再extends Thread),所以可以实现一个Runnable接口。

public class RunnableThreadTest extends *** implements Runnable {
	private int i;

	public void run() {
		for (i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + " " + i);
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + " " + i);
			if (i == 20) {
				//需要首先实例化一个Thread
				RunnableThreadTest rtt = new RunnableThreadTest();
				new Thread(rtt, "新线程1").start();
				new Thread(rtt, "新线程2").start();
			}
		}
	}
}

3.通过Callable和Future创建线程
有返回值的任务必须实现Callable接口(无返回值实现Runnable接口),执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。

实现call()方法,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值,使用FutureTask对象作为Thread对象的目标创建并启动新线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableThreadTest implements Callable<Integer> {

	public static void main(String[] args) {
		CallableThreadTest ctt = new CallableThreadTest();
		FutureTask<Integer> future = new FutureTask<>(ctt);
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "的循环变量i的值==" + i);
			if (i == 5) {
				new Thread(future, "有返回值的线程=").start();
			}
		}
		try {
			//获取Callable任务返回的Object
			System.out.println("子线程的返回值:" + future.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}

	}

	@Override
	public Integer call() throws Exception {
		int i = 0;
		for (; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + " " + i);
		}
		return i;
	}

}

4.基于线程池的方式
使用线程池创建线程就跟使用数据库连接池类似,都是为了节省资源。需要注意的是,Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具,真正的线程池接口是ExecutorService。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceTest {

	public static void main(String[] args) {
		// 创建线程池
		ExecutorService threadPool = Executors.newFixedThreadPool(10);
		while (true) {
			threadPool.execute(new Runnable() { // 提交多个线程任务,并执行
				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName() + " is running ..");
					try {
						Thread.sleep(3000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
	}

}

>>>>>创建方式的对比<<<<<
使用继承Thread类的方式创建多线程
A.优势是:编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

B.劣势是:线程类已经继承了Thread类,所以不能再继承其他父类。

采用实现Runnable、Callable接口的方式创见多线程
优势是:
1)适合多个线程进行资源共享
2)避免java中单继承的限制
3)增加程序的健壮性,代码和数据独立
4)线程池只能放入Runable或Callable接口实现类,不能直接放入继承Thread的类

劣势是:编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

Callable和Runnable有何区别?
1)Callable重写的是call()方法,Runnable重写的方法是run()方法
2)call()方法执行后有返回值(返回值是泛型),run()方法没有返回值(void)
3)call()方法可以抛出异常,run()方法不可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值