并发、锁、安全、线程池
1 引言
并发编程的优点与缺点
- 从资源利用率的角度考虑,并发编程可以提高系统的资源利用率,最常见的是等待IO或等待HTTP返回与CPU资源浪费的矛盾。在并发的程序中CPU可以在等待这些低速设备时运行程序中的并发部分,这可以显著提高CPU资源的利用率。在多核计算机中并发也更容易发挥多核的优势。由于并发编程中的程序切换需要消耗一定的资源,所以并不是进程越多越好。
- 从公平性考虑,在一些设计场景中,比如多用户和程序对计算机资源具有同等的使用权。这用并发编程的时间片分配就可以很容易实现。
- 从编程的便利性考虑,在某些解决问题时,并发编程更容易模拟客观场景,解决这些问题。
- 安全性问题。由于并发执行的场景下,程序的执行先后顺序是不可预测的,这就会导致一些错误。典型的是并发i++、if-do例子。
- 活跃性问题。指的是正常的操作无法继续执行下去的问题,安全性问题考虑的是『永远不发生糟糕的事情』,活跃性问题考虑的是『某件正确的事情最终会发生』。也就是不要出现死锁、饥饿、活锁(一直在做无用功)现象。
- 性能问题。比如多线程的并发,线程切换也是需要资源消耗的,如果发生了频繁的线程切换,这也是巨大的资源浪费。
2 线程、进程、多线程
2.1 多任务
特征:一个对象在同一时间同时操作多个任务,由于操作多任务时切换时间非常短被视为多任务。
案例:一边上厕所一边看手机、一边吃饭一边看手机…
2.2 多线程
引例问题:单条道路在早晚高峰期产生车辆拥堵。
解决方案:开辟多条道路加速车流量的吞吐。
2.3 程序、进程、线程
一个进程可以有多个线程。
如:在一个视频中同时看图像、听声音、发弹幕等
2.3.1 进程(Process)与线程(Thread)
- 提及进程就需要说到程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
- 而进程则是执行程序的一次执行过程,它是一个动态概念。是系统资源分配的单位。
- 通常在一个进程中可以包含多个线程,一个进程中至少包含一个线程,否则没有存在意义。线程是CPU调度和执行的单位。
注记:很多多线程是模拟出来的,真正的多线程是有多个CPU(多核、服务器)如果是模拟出来的多线程(单核CPU)在同一个时间点只能执行一个代码,因为切换的速度很快,所以产生了多线程的错觉。
2.4 概念小结
- 线程就是独立执行的路径
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程:主线程、垃圾回收线程等。
- main()被称作为主线程,为系统的入口,用于执行整个程序。
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度。调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。
- 对同一份资源操作时,会存在资源抢夺问题,需要引入并发控制。
- 线程会带来额外的开销,如:CPU调度时间、并发控制开销等。
- 每个线程在自己的工作内存中交互,内存控制不当会造成内存不一致。
3 继承Thread类
3.1 线程创建的三种方式
3.2 Thread类
package cn.dioxide.program;
//创建线程方式1:继承Thread类
//线程开启不一定立即执行,由CPU的调度决定
public class ThreadPack extends Thread {
@Override
public void run() {
//重写线程的run方法
for (int i = 0; i < 20; i++) {
System.out.println("线程执行"+i);
}
}
public static void main(String[] args) {
//创建线程对象
ThreadPack tp = new ThreadPack();
//start方法启动线程
tp.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程执行"+i);
}
}
}
4 网络图片下载功能
需要外Jar包commons-io-2.11.0.jar
太简单,略。
见:【狂神说Java】多线程详解 网图下载
评论区