做实验的过程中需要用到多线程,许久不用有点儿生疏了,现在查资料做个多线程创建的方法记录。

Java使用线程大致有以下四种方法:

1.继承Thread类,重写run方法

每次创建一个新的线程,都需要新建一个Thread子类的对象。
一个线程调用两次start()方法将会抛出线程状态异常。
继承Thread类的方式是多个线程各自完成各自的任务。
创建线程实际调用的是父类Thread空参的构造器。

public class Test {
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			MyThread thread = new MyThread();
			thread.satrt();
		}
		System.out.println("This is main thread");
	}
}

public class MyThread extends Thread {
	@Override
	public void run() {
		System.out.println("This is MyThread.");
	}
}

2.实现Runnable接口,重写run()方法

覆写Runnable接口实现多线程,可以避免单继承局限。不论创建多少个线程,只需要创建一个Runnable接口实现类的对象。
创建线程实际调用的Thread类Runnable类型参数的构造器。
实现Runnable接口的方法可以多个线程共同完成一个任务。

public class Test {
	public static void main(String[] args) {
		Task task = new Task();
		for (int i = 0; i < 10; i++) {
			Thread thread = new Thread(task);
			thread.satrt();
		}
		System.out.println("This is main thread");
	}
}

public class Task implements Runnable {
	@Override
	public void run() {
		System.out.println("This is MyThread.");
	}
}

3.实现Callable接口,重写call()方法

自定义类实现Callable接口时,必须指定泛型,该泛型即返回值的类型。
每次创建一个新的线程,都需要创建一个新的Callable接口的实现类。
启动线程的过程:

public class Test {
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			Task task = new Task();
			FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
            Thread thread = new Thread(futureTask);
            thread.start();
            try {
                System.out.println("The result is : " + futureTask.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
		}
		System.out.println("This is main thread");
	}
}

public class Task implements Callable<Integer> {
	@Override
	public Integer call() {
		int result = 0;
		for (int i = 0; i < 10000; i++)
			result += i;
		return result;
	}
}

FutureTask的get()方法在调用的时候会阻塞,直到当前的线程完成运行后将结果返回。

4.使用线程池

在java.util.concurrent包下,提供了一系列与线程池有关的类。合理使用线程池,可以带来诸多好处:

这里使用一个固定大小的线程池来举例子。

public class Test {

	private static final int THREAD_POOL_SIZE = 5;

	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
		Task task = new Task();
		FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
		executorService.submit(futureTask);
		executorService.shutdown();
		try {
			System.out.println("The result is : " + futureTask.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		System.out.println("This is main thread");
	}
}

public class Task implements Callable<Integer> {
	@Override
	public Integer call() {
		int result = 0;
		for (int i = 0; i < 10000; i++)
			result += i;
		return result;
	}
}

5.对比

可以将java中的线程创建方式分为两大类:一类是继承Thread类实现多线程;另一类是通过实现Runnable或者Callable接口实现多线程。
下面来分析一下这两类实现多线程方式的优劣:

通过继承Thread实现多线程

通过实现Runnable或Callable接口实现多线程

综上 :使用第二类方法较多!