①继承Thread类的方式
将一个类声明为Thread
的子类。 这个子类应该重写run
类的方法Thread
。 然后可以分配并启动子类的实例。
例如,计算大于规定值的素数的线程可以写成如下:
class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
然后,以下代码将创建一个线程并启动它运行:
PrimeThread p = new PrimeThread(143); p.start();
②实现Runnable接口的方式
创建一个线程是声明实现类Runnable
接口。 那个类然后实现了run
方法。 然后可以分配类的实例,在创建Thread
时作为参数传递,并启动。
这种其他风格的同一个例子如下所示:
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
然后,以下代码将创建一个线程并启动它运行:
PrimeRun p = new PrimeRun(143); new Thread(p).start();
每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。
除非另有说明,否则将null
参数传递给null
中的构造函数或方法将导致抛出NullPointerException
。
③利用Callable接口和Future接口方式
/*
* 多线程的第三种实现方式
* 可以获取多线程运行的结果
* 1.创建一个类MyCallable实现Callable接口
* 2.重写call() 注意拥有返回值,这个返回值就是多线程运行的结果
* 3.测试类中创建MyCallable的对象(多线程执行的任务)
* 4.创建FutureTask的对象(作用管理多线程运行的结果)
* 5.创建Thread的对象(表示线程),并启动
* */
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread t1 = new Thread(ft);
t1.start();
Integer result = ft.get();System.out.println(result);
对比
①
优点:编程比较简单,可以直接使用Thread类中的方法
缺点:扩展性较差,不能再继承其他的类
②、③
优点:扩展性强,实现该接口的同时还可以继承其他的类
缺点:编程相对复杂,不能直接使用Thread类中的方法