1、多线程
了解线程之前我们必须要先了解(程序—>进程—>线程)的过程
程序:是一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具。
进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
总之一个程序至少有一个进程,一个进程至少有一个线程。
那么如果要想实现一个多线程的主类,有两类途径:
集成一个Thread类
实现Runnable、Callable接口。
1、继承Tread类
1)、定义一个实现类继承于Thread类
2)、重新run方法
3)、启动程序new实现类,调用start()方法:当调用run方法时,run方法将会在主线中调用,依旧是单线程。
public class TestThread {
public static void main(String[] args) {
//new 定义的类
MyThread myThread = new MyThread();
//使用start()方法启动线程
myThread.start();
//main线程也启动
for (int i = 0; i < 10; i++) {
System.out.println("我是main线程:"+i);
}
}
}
//新建一个类继承Thread
class MyThread extends Thread{
//重写Thread类中的run方法
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我是线程:"+Thread.currentThread().getName()+":"+i);
}
}
}
2、实现Runnable接口
1)、创建当前类实现Runnadble接口
2)、重新run方法
3)、在主线程main中启动线程,这里启动时需要new Thread对象并将当前类放入Thread对象中,再启动Thread方法中的start()方法。
注意:因为Thread也是实现Runnable,且Runnable是一个函数式接口满足lamdba表达式运行:new Thread(lamdba表达式).start();
public class TestThread02 {
public static void main(String[] args) {
//启动线程方法一
// MyRunnableThread runnableThread = new MyRunnableThread();
// new Thread(runnableThread).start();
// 使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我是线程:"+Thread.currentThread().getName()+":"+i);
}
}
}).start();
// 使用lamdba表达式启动:因为Runnable是一个函数式接口(在匿名类不类中更加简化)
new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println("我是线程:"+Thread.currentThread().getName()+":"+i);
}
}).start();
//main线程也启动
for (int i = 0; i < 10; i++) {
if(i>=5){
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("我是main线程:"+Thread.currentThread().getName());
}
}
}
//新建一个类实现Runnable接口
class MyRunnableThread implements Runnable{
//重新run方法
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我是线程:"+Thread.currentThread().getName()+":"+i);
}
}
}
3、实现Callable接口
1)、定义类实现Callable接口
2)、重写call方法(call方法有返回值)
3)、new 实现对象
4)、new FutureTask 实现类 用于接收运算结果。(它们都是java.util.concurrent包下的类)
5)、new Thread(FutureTask对象返回的数据).start(); 启动
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class TestCallableThread {
public static void main(String[] args) {
//new 实现对象
MyCallable myCallable = new MyCallable();
//new FutureTask 实现类 用于接收运算结果。 FutureTask 是 Future 接口的实现类
FutureTask<Boolean> task = new FutureTask<Boolean>(myCallable);
//new Thread
new Thread(task).start();
//main线程也启动
for (int i = 0; i < 10; i++) {
if(i>=5){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("我是main线程:"+Thread.currentThread().getName());
}
//call方法 返回的接口
try {
final Boolean aBoolean = task.get();
System.out.println("返回的结果:"+aBoolean);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//定义类实现Callable接口
class MyCallable implements Callable{
//重写call方法
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("我是线程:"+Thread.currentThread().getName()+":"+i);
}
return true;
}
}
Callable 和 Future接口的区别:
(1)Callable规定的方法是call(),而Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call()方法可抛出异常,而run()方法是不能抛出异常的。
(4)运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
运行结果:
注:上面三种只是单纯的启动多个线程,并不安全!!!