一、多线程介绍
1.什么是多线程
在学习多线程前,我们先简单了解一下什么是线程;线程可能大家平常比较少见,但是相信大家对进程这个词都不陌生,所谓进程可以理解为一个进行中程序,最常见的一个例子就是平常有程序卡死了,我们就会打开任务管理器去结束掉这个进程,如下图:
而线程其实和进程大同小异,进程是操作系统中的一个独立的模块,而线程就是进程中的一个独立的模块,一个操作系统中执行多个程序就是多进程,一个进程执行多个线程就是多线程。
2.为什么要用多线程
很简单,提高效率,举个例子,你如果要洗衣服,你肯定会先让洗衣机放水。然后在放水时把脏衣服收拾出来放到洗衣机里,然后放洗衣液进去,之后在等洗衣机洗衣服的同时去把衣架整理出来,而不是等洗衣机水放完了才放洗衣液,然后放衣服,等衣服洗完了才去找衣架,虽然只有一个人,但是同时为了洗衣服同时做好几件事情,这样效率就可以大大提高;在计算机中,一个CPU就可以看成一个人,洗衣服可以看成一个进程,放水、收拾衣服、找衣架就相当与是多个线程,利用好多线程就可以在主线程执行任务的同时可以执行其他任务,而不需要等待。
二、在Java中如何创建线程
1.继承Thread类
创建步骤
(1)创建多线程类继承Thread;
(2)重写Thread中的run方法,run中用来添加线程的方法;
(3)在主函数中创建实例;
(4)用创建的实例调用run方法;
下面是一个例子
public class ThreadTest extends Thread{
public static void main(String[] args) {
ThreadTest t1 =new ThreadTest();
ThreadTest t2 =new ThreadTest();
ThreadTest t3 =new ThreadTest();
double start = System.currentTimeMillis() ;
t1.run();
t2.run();
t3.run();
double end = System.currentTimeMillis() ;
System.out.println("time is : " + (end - start));
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+":正在执行!"+i);
}
}
}
可以看到在这个例子中我添加了一个计算程序运行时间的方法,这个方法验证了上面所说到多线程高效率,注意看下图中的线程数和时间。
可以明显的看出来,执行一个线程所需要的时间和执行三个线程所需要的时间是一样的,而不是和线程数量成正比。
2.实现Runable接口
创建步骤
(1)创建类实现Runnable接口
(2)重写Runnable接口中的run方法,run中用来添加线程的方法。
(3)创建Runable实例,创建Thread实例建立线程对象,将Runnable实例对象作为实际参数传递给Thread对象
(4)用Thread的实例对象调用start方法
class RunableTest implements Runnable {
public static void main(String[] args) {
Runnable runn = new RunableTest();
Thread thread = new Thread(runn);
Thread thread2 = new Thread(runn);
thread.start(); thread2.start();
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程执行!"+i);
}
}
}
看到这里,相信不少人和我之前一样有一个疑问,Thread和Runable有什么区别呢,为什么要实现Runable接口呢?
Thread和Runable本质上只有一个区别,那就是一个是类一个是接口,Runable没有单继承的限制(其实Thread也是继承了Runable接口的)
3通过Callable和Future实现多线程
创建步骤
(1)创建线程类继承Callable,重写call()方法,这个call()用来添加该线程的方法,和Runable不同的是它有返回值。
(2)创建Callable实现类的实例对象,创建FutureTask的实例对象,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的参数创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得线程执行结束后的返回值
class CallableTest implements Callable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableTest callableTest = new CallableTest();
FutureTask futureTask = new FutureTask(callableTest);
new Thread(futureTask).start();
Object result = futureTask.get();
System.out.println(result);
}
@Override
public String call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("线程执行!" + i);
}
return "运行结束";
}
//运行结果
线程执行!0
线程执行!1
线程执行!2
线程执行!3
线程执行!4
线程执行!5
线程执行!6
线程执行!7
线程执行!8
线程执行!9
运行结束