目录
一.进程和线程
1.什么是进程
2.并发,并行和串行
3.线程和多线程
4.进程和线程的区别(重点)
5.多线程的优点
6.多线程的缺点
二.线程的创建
1.继承Thread类
2.实现Runnable接口重写run()方法
3.通过匿名内部类的方式创建Thread和实现Runnable
4.通过Lambda表达式来实现一个线程
三.查看Java中创建线程的状态
1.直接到JDK中寻找jconsole.exe文件
2.命令行中直接搜索jconsole
一.进程和线程
1.什么是进程
在计算机中,进程是指正在运行的程序的实例。进程是操作系统进行资源分配和调度的基本单位。
每个进程都有其独立的内存空间和数据栈,使得它们之间相互隔离,避免了不同进程之间的数据干扰。操作系统通过分配资源,管理进程间的调度,使得进程可以有序、并发地运行。同时,进程之间也可以通过各种通信机制进行数据传输和共享,这些通信机制可以使不同进程之间协同工作,共同完成任务。
进程可以处于不同的状态,例如运行、就绪、堵塞等,进程状态的变化可以由内部事件和外部事件引起。内部事件包括程序的运行、资源的申请和释放等,而外部事件则包括输入/输出请求、信号等。操作系统会根据不同的事件,将进程切换到不同的状态,以便对进程进行管理和调度。
2.并发,并行和串行
串行(Serial)指的是一个任务或进程按顺序逐个完成,一个任务完成后,另一个任务才开始执行。例如,一个计算机需要处理多个任务,这个时候串行是一个任务执行完毕之后,才能处理下一个任务.
并发(Concurrent)指的是多个任务在相同时间段内交替执行。在单处理器系统中,实现并发需要快速地在多个任务之间切换。例如,一个计算机需要同时运行多个应用程序,每个应用程序都有一个单独的进程,操作系统需要在这些进程之间快速地切换。
并行(Parallel)指的是多个任务同时执行,每个任务在不同的处理器上独立运行。并行需要多个处理器或多个计算机来同时执行不同的任务。例如,一个大型计算任务被分成多个子任务,每个子任务分配到不同的处理器或计算机上执行。
在计算机领域中,并行和并发的概念通常被用来提高系统性能和响应能力。通过同时执行多个任务或进程,可以最大限度地利用计算机系统的资源。而串行则在某些情况下更为简单和可控,例如在单线程程序或少量任务的情况下。
再来举一个生活中的例子,当我们在吃饭(任务A)的时候,这个时候电话铃响了.
①串行:我们需要吃完饭之后,才能进行接电话(任务B).
②并发:我们一会去接电话,一会吃饭,同时只进行一个任务,但是可以快速的切换这两个任务,一会进行任务A,一会进行任务B.
③并行:我们一边吃饭,一边接电话,任务A和任务B同时进行
3.线程和多线程
多线程是指在一个进程中同时运行多个线程的技术。线程是指一个程序内部的执行路径,每个线程都拥有自己的堆栈和寄存器,并且能够访问共享内存中的变量和对象。与进程相比,线程是轻量级的,一个进程可以同时拥有多个线程。
为什么要存在线程呢?
根据上面定义我们可以知道线程是轻量级的.多线程的开辟比多进程的开辟更能解决资源的消耗问题.下面是进程开辟时需要进行的操作:
这样显然是十分消耗内存的,因此便有了线程
创建线程只关注要处理的任务,使用的是进程创建时申请到的所有资源
案例:创建工厂
张三需要创建工厂生产生活用品,他需要在厂区申请一块地皮创建工厂(CPU给进程分配资源),工厂就相当于一个线程,这个厂区还有其他的工厂,别人的工厂(其他的线程),他们之前生产的东西之间互不影响.然后张三的工厂里面有需要的生产线(线程),负责生产不同的产品(也可能不同的生产线生产相同的产品),各个生产线之间可以相互影响(线程可以相互影响).申请地皮创建工厂的花费是很大的,需要建设厂房,购买基础设施等等(进程的创建的代价很大),而一条生产线可以相对容易的创建(线程的创建较容易).因此张三需要夸大生产,可以优先考虑创建生产线(进程)
4.进程和线程的区别(重点)
- 对于进程而言,至少有一条线程(主线程).
- 进程是申请系统资源的最小单位.
- 线程是CPU调度的最小单位.
- 进程之间互不影响,线程之间可以互相影响.
5.多线程的优点
- 充分利用CPU的资源
- 利用轻量级线程的特性减少系统的开销
a.线程创建的效率比进程高 b.线程销毁的效率比进程高 c.线程调度的效率比进程高
6.多线程的缺点
多线程也可以存在一些问题
这里我们拿小呆呆吃100个棒棒糖为例
如何我们使用多进程的话,需要的是两个桌子,每个桌子各放50个棒棒糖,然后进行吃
如果采用多线程的模式化,只需要在一个桌子上多增加几个小呆呆进行吃
但是可能会发生这样一个问题,当我们不断的增加小呆呆的数量,小呆呆达到一定的数量之后,这样不但没有提高效率,反而会给CPU增加负担.因此在真实的程序中,确定线程的数量,需要反复的测试.
还有可能出现以下问题
当还有一个棒棒糖的时候.,但这是有两个小呆呆,这个时候两个小呆呆争抢一个棒棒糖,会出现线程不安全的问题.
二.线程的创建
Java中的JDK给我们提供了API来创建线程(Thread类)
1.继承Thread类
public class Demo2_Thread {
public static void main(String[] args) {
MyThread02 thread02 = new MyThread02();
thread02.start();
while (true){
System.out.println("main thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class MyThread02 extends Thread{
@Override
public void run() {
while (true){
System.out.println("my thread ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
run()方法中表示的就是这个线程中需要执行的任务
注意: 我们自定义的继承的Thread的类重写的是run()方法,而我们启动的线程的时候调用的是start()方法,如果我们调用成了run()方法,就仅仅是类中一个方法的调用,而start()方法才是创建一个线程,具体我们可以看一下源码start()方法.
代码的运行结果
从代码的运行结果我们可以总结出两个线程(主线程main和my thread)并不是有序执行的,因为CPU的调度是随机的. 线程的执行是抢占式执行
2.实现Runnable接口重写run()方法
public class Demo3_Runnable {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
//创建线程
Thread thread = new Thread(myRunnable);
thread.start();
while (true) {
System.out.println("main thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class MyRunnable implements Runnable {
//需要执行的任务
@Override
public void run() {
while (true) {
System.out.println("生产皮包,金币+1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
使用Runnable定义任务的好处:
1.解耦,把定义线程和定义任务分开
2.将定义线程和定义任务分开 ,以便修改代码时可以统一的进行修改
解耦:把不同的功能分开,如何要修改或查找指定的功能的代码可以到指定位置进行操作.
3.通过匿名内部类的方式创建Thread和实现Runnable
public class Demo4_Annoation {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
while (true) {
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
thread.start();
while (true){
System.out.println("main thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
4.通过Lambda表达式来实现一个线程
对Lambda表达式不熟悉的可以看这一篇博客:Java8新特性之Lambda表达式和Stream API
public class Demo5_Lambda {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true) {
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
while (true){
System.out.println("main thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
其实这个就是类似于实现Runnable,因为Runnable接口是一个函数式的接口,而且其中的方法run()没有参数,所以可以直接用上面的格式进行实现, 大括号里面就是线程需要执行的功能
三.查看Java中创建线程的状态
1.直接到JDK中寻找jconsole.exe文件
双击打开,找到自己运行的线程进行查看
点击不安全连接进行查看
点击上方的线程,查看自己的线程信息,默认的线程Thread0开始,也可以在代码中给自己的线程进行命名操作