本文讲解Java创建多线程的三种方法,分为以下四部分:
一、继承Thread类
二、实现Runnable接口
三、实现Callable接口
四、实例
一、继承Thread类
步骤:1)定义一个类继承Thread;
2)重写run方法;
3)创建线程对象;
4)调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。
代码1:
1)创建子类继承Thread:
public class SubThread extends Thread{
public void run(){
for (int i = 0; i < 50; i++) {
System.out.println("run..."+i);
}
}
}
2)实例:
public class ThreadDemo {
public static void main(String[] args) {
SubThread subThread = new SubThread();
subThread.start();
for (int i = 0; i < 5; i++) {
System.out.println("main..."+i);
}
}
}
运行结果:
代码2:匿名内部类的形式
public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
new Thread(){
public void run(){
System.out.println("匿名内部类");
}
}.start();
}
}
二、实现Runnable接口
步骤:1)定义类实现Runnable接口;
2)覆盖接口中的run方法;
3)创建Thread类的对象;
4)将Runnable接口的子类对象作为参数传递给Thread类的构造函数;
5)调用Thread类的start方法开启线程。
代码1:
1)创建子类实现Runnable接口:
public class SubRunnable implements Runnable {
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("run..." + i);
}
}
}
2)实例:
public class ThreadDemo {
public static void main(String[] args) {
SubRunnable subThread = new SubRunnable();
Thread t = new Thread(subThread);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("main..." + i);
}
}
}
运行结果:
代码2:匿名内部类形式:
public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
//方式一
Runnable runnable = new Runnable(){
public void run(){
System.out.println("匿名内部类1");
}
};
new Thread(runnable).start();
//方式二
new Thread(new Runnable() {
public void run() {
System.out.println("匿名内部类2");
}
}).start();
}
}
三、实现Callable接口
Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。
- Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能。
- Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
在此之前先看下线程池(java.util.concurrent下):
步骤:1)创建线程池对象;
2)创建Runnable接口子类对象;
3)提交Runnable接口子类对象;
4)关闭线程池。
代码:
1)创建Runnable子类对象:
public class ThreadPoolRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + "线程池任务");
}
}
2)实例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new ThreadPoolRunnable());
executorService.submit(new ThreadPoolRunnable());
executorService.submit(new ThreadPoolRunnable());
//关闭
executorService.shutdown();
}
}
结果:
Callable方式步骤:
1)创建线程池对象;
2)创建Callable接口子类对象;
3)提交Callable接口子类对象;
4)关闭线程池。
代码:
1)创建Callable子类对象:
import java.util.concurrent.Callable;
public class ThreadPoolCallable implements Callable<String> {
public String call() throws Exception {
return "callable thread";
}
}
2)实例:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolCallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<String> future = executorService.submit(new ThreadPoolCallable());
//获取返回值
String s = future.get();
System.out.println(s);
}
}
结果:
四、实例
使用多线程技术求和,1个线程计算1+100,另一个线程计算1+200
代码:
import java.util.concurrent.Callable;
public class GetSumCallable implements Callable<Integer> {
private int aa;
public GetSumCallable(int aa){
this.aa = aa;
}
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= aa; i++) {
sum = sum + i;
}
return sum;
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Integer> f1 = es.submit(new GetSumCallable(100));
Future<Integer> f2 = es.submit(new GetSumCallable(200));
System.out.println(f1.get());
System.out.println(f2.get());
es.shutdown();
}
}
结果:
思考:线程对象调用run方法和start方法的区别?
线程对象调用run方法不开启线程,仅是对象调用方法。线程对象调用start开启线程,并让jvm调用run方法在开启的线程中执行。