文章目录
1 进程与线程
1.1 进程与线程的概念
Java是第一门原生支持多线程的高级语言
什么是进程?
进程: 在一个操作系统中,每个独立执行的程序都可称之为一个进程,也就是“正在运行的程序”。Windows操作系统下,鼠标右键单击任务栏,选择【启动任务管理器】选项可以打开任务管理器面板,在窗口的【进程】选项卡中可以看到当前正在运行的程序,也就是系统所有的进程。
多进程: 同一时刻跑多个(进程)程序。比如我们在用腾讯视频看电视的时候照样可以登录qq和朋友聊天
在DOS(磁盘操作系统时代),由于其本身就是一个单进程的操作系统,所以在同一时间段上只能够有一个程序执行;后来发展到Windows系统后,我们可以发现多个程序可以同时执行,所以Window是一个多进程的操作系统。现在基本上所有的操作系统都是多进程。
什么是多线程?
一个程序(进程)可以执行多个任务,通常,每一个任务就称之为一个线程。登录qq和朋友聊天,此时肯定存在读线程和写线程同时运行。
1.2 对比进程、线程
- 与进程相比,线程更加的轻量级,创建、撤销一个线程比启动、撤销一个进程开销要小的多,并且一个进程中的所有线程共享此程序(进程)的所有资源。
- 没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。就像你登录QQ和朋友聊天,如果某一时刻你关掉了QQ,读线程和写线程也将不复存在
- 进程是操作系统资源调度的基本单位,进程可以独享资源;线程需要依托进程提供的资源,无法独立申请操作系统资源,是操作系统任务执行的基本单位。
多进程与多线程的区别?
本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据,共享变量使得线程之间的通信比进程之间的通信更加有效方便。
1.3 高并发
高并发指的是:同一时刻线程的访问量非常高。
高并发带来的问题:服务器内存不够用,无法处理新的请求
1.4 线程的状态
2 Java的多线程实现
2.1 继承Thread类实现多线程
java.lang.Thread
是一个线程操作的核心类,(java.lang包会自动导入,所以不需要手动书写)新建一个线程最简单的方式就是直接继承Thread类,而后覆写该类中的run()方法。(就相当于主线程的main方法,每个线程都应该有一个入口,主方法是主线程的入口,run方法是线程入口
)
继承Thread定义线程:
class MyThread extends Thread{
private String title;
public myThread(String title) {
this.title = title;
}
@Override
public void run() //所有线程从此处开始运行
{
for(int i=0;i<10;i++)
{
System.out.println(this.title+" i="+i);
}
}
}
新建一个线程最简单的方式就是继承Thread类,而后覆写该类中的run()方法,很自然我们就想到产生线程类的实例化对象而后调用run()方法。
显然,这个时候只做了顺序打印,和多线程一点关系都没有(多线程的意思是任务同时进行所有不可能顺序打印)可见启动多线程的方式错误。
启动多线程:public synchronized void start()
此方法会自动调用线程的run()方法
无论哪种方式实现多线程,线程启动一定调用Thread类的start()
方法,而不是直接对象名.run()
看start()的源码:
- 首先我们看到在start()方法中抛出
IllegalThreadStateException
线程状态异常,按照原有处理方式,应当在调用处进行异常处理,然而此处没有处理也不会报错,因此是一个RunTimeException(非受查异常),这个异常的产生只是因为你重复启动了线程才会产生,所以每一个线程对象只能够启动一次
- 我们看到在start()方法中调用了start0()方法,而这个方法是一个只声明而未实现的方法,同时使用native关键字进行定义。
private native void start0();
native指的是调用本机的原生系统函数:(方法体在C语言中实现)
Thread类有个 registerNatives 本地方法,该方法主要的作用就是注册一些本地方法供 Thread 类使用,如 start0(),stop0() 等等,可以说,所有操作本地线程的本地方法都是由它注册的。
这个方法放在一个 static 语句块中,当该类被加载到 JVM 中的时候,它就会被调用,进而注册相应的本地方法。而本地方法 registerNatives 是定义在 Thread.c 文件中的。
Thread.c 是个很小的文件,它定义了各个操作系统平台都要用到的关于线程的公用数据和操作,如下:
观察上边一小段代码,可以容易的看出 Java 线程调用 start->start0 的方法,实际上会调用到 JVM_StartThread 方法,那这个方法又是怎么处理的呢?
综上可知,Java线程创建的调用流程为::调用Thread类的start()(Java方法)方法,判断线程是不是新创建的,如果不是新创建的抛出IllegalThreadStateExcepti