关于线程的那些事……
前言
从今天开始我们要再次重新学习多线程的相关内容,至于为什么要学习多线程,原因很简单,java
是一门流行的web
端开发语言,而web
应用中有一个核心的要素就是效率,也就是快速响应用户的需求,但是随着业务的不断发展,业务环境的复杂化,单一流程的应用很难满足高效率的需求,所以多线程就有了用武之地。
线程
基本知识点
什么是线程
线程是进程中独立运行的子任务,也是程序运行的最小单位。通常情况下,一个进程可以包括多个线程。如果你有仔细观察过电脑任务管理的详细信息的话,你一定对下面这张图片不陌生:
从这张图中我们可以看出计算机的进程数、线程数等数据,这里的线程数就包括java
软件运行时的线程,另外,我们从这张图还可以看出来,线程数远远大于进程数,这也从侧面佐证了一个进程可以包含多个线程。
串行与并行
说到多线程就避不过串行和并行的话题,串行就是程序的每一行代码依次执行,在大多数的场景下,后面执行的代码,要依托于前面代码的执行结果,或者说是后面的代码必须在前面的代码执行完成之后才能被执行;而并行就是代码直接没有任何依赖关系,代码与代码之间也没有任何的运行顺序,两段代码可以同时运行,当然,这样说虽然也不完全对,但也算说清楚了并行与串行的应用场景。
说了这么多,下面我们说一些干货:
串行就是我们常说的单线程,必须按照指定的顺序运行,所以效率低下,但同时却可以确保顺序 并行就是我们常说的多线程,线程与线程之间的执行是没有顺序可言的,所以会存在线程安全问题,但是效率比较高
举一个很形象的例子来说明并行和串行,假设你有十件事需要做,按照串行的方式的话,你必须得一件一件地做事,一件事没有完成的时候,是不可以进行下一件事的;按照并行逻辑的话,你可以同时做这十件事,只要你有时间,你就可以选择任意一件事来做,当然如果你要是会分身术的话,那就叫真并发运行了(这就特别类似单核CPU
和多核CPU
,单核的时候只能来回切换以提高利用效率,多核的时候就真的可以同时运行多个任务)
创建方式
关于线程的创建方式有三种,一种是直接通过继承Thread
类的方式。
Thread
这也是最原始的创建方式:
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("run 方法开始执行了");
}
public static void main(String[] args) {
new MyThread().start();
}
}
这种方式的缺点很明显,因为在java
中,一个类只能继承一个类,所以如果一个类已经继承了父类,它就再没办法通过继承Thread
来实现多线程了,于是就有了第二种方式——Runnable
接口
Runnable
runnable
接口就比Thread
类要灵活的多,因为java
的接口是运行多实现的,所以一个类实现了其他接口以后,依然可以实现Runnable
接口:
public class RunnableDemo extends Observable implements Runnable {
@Override
public void run() {
System.out.println("我是继承了Thread,并实现了Runnable的类");
}
public static void main(String[] args) {
new Thread(new RunnableDemo()).start();
}
}
但是runnable
本身是没法靠自己启动的,它必须通过Thread
或者线程池来启动,如果直接调用run
方法,也只能是像普通方法一样执行。
虽然Runable
比Thread
要灵活,它也能实现我们绝大多数的应用场景,但是在某些应用场景下,它也显得很无能为力,比如run
方法需要返回值,这时候callable
应运而生。
Callable
相比于Thread
和Runnable
,Callable
就是小萌新,因为它是JDK1.5
才引入的,而前两个是从JDK1.0
就已经存在了:
由于比较萌新,所以Callable
的运行方式也比较特殊,只能通过线程池启动:
public class CallableDemo implements Callable<String> {
@Override
public String call() throws Exception {
return "hello callable";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Future submit = Executors.newSingleThreadExecutor().submit(new CallableDemo());
String s = submit.get();
System.out.println(s);
}
}
结语
单就线程的知识点来说,这块还是比较简单的,大多都是一些基础的概念,但还是要扎实理解其中的一些要点,这里我们做一个简单的梳理:
线程是程序运行的最小单元 线程可以理解为在进程中独立运行的子任务 一个进程可以包含多个线程 多线程的特点是在同一时间执行多个任务 多线程就是通过使用异步技术,提高处理器的利用效率
最后,希望各位小伙伴记住一句话:不要为了使用多线程而使用多线程,要结合实际业务场景分析。好了,今天就到这里吧,各位小伙伴,晚安吧!
- END -