多线程学习笔记
多线程学习
进程与线程
进程
程序运行的载体。至少有 5 种基本状态:初始态,执行态,等待状态,就绪状态,终止状态
线程
线程是程序执行时的最小单位,线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源
进程和线程的关系
线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
进程是资源分配的最小单位,线程是程序执行的最小单位。
进程和线程的区别
理解它们的差别,我从资源使用的角度出发。(所谓的资源就是计算机里的中央处理器,内存,文件,网络等等)
根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
开销方面:每个进程都有独立的代码和数据空间(程序上下文),进程之间切换开销大;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小
所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
内存分配:系统为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
包含关系:线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程
在程序运行时,即使没有自己创建线程,后台也会有多个进程,如主进程,gc进程;
在一个进程中,如果开辟了多个线程,线程的运行由调度器(cpu)安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的;
-
多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
-
并行与并发:
-
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
-
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
-
并发与并行
-
线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:
void transferMoney(User from, User to, float amount){
to.setMoney(to.getBalance() + amount);
from.setMoney(from.getBalance() - amount);
} -
同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入
@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。
线程的实现
线程的几种实现方式
继承Thread类
Thread01类
package com.aly.dxc;
/**
* @author aly
* @version 1.0
* @date 2020/10/19 20:14
*/
//线程创建学习:继承Thread类 重写run()方法编写线程执行体 创建线程对象,调用start()启动线程
public class Thread01 extends Thread {
!(C:\Users\luoHison\AppData\Roaming\Typora\typora-user-images\image-20201019211724129.png)
Thread02类
package com.aly.dxc;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* @author aly
* @version 1.0
* @date 2020/10/19 20:47
*/
//联系Thread,实现多线程同步下载图片
public class Thread02 extends Thread{
public String url;
public String fileName;
public Thread02(String url, String fileName) {
this.url = url;
this.fileName = fileName;
}
//下载图片线程的执行体
实现Runnable接口
Runnable01类
package com.aly.dxc;
/**
* @author aly
* @version 1.0
* @date 2020/10/19 20:14
*/
//线程创建学习:实现runnable接口 重写run()方法 执行线程需要丢入runnable接口实现类 调用start()方法
public class Runnable01 extends Thread {
Runnable02类
package com.aly.dxc;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* @author aly
* @version 1.0
* @date 2020/10/19 20:47
*/
//练习实现Runnable接口,实现多线程同步下载图片
public class Runnable02 implements Runnable{
public String url;
public String fileName;
public Runnable02(String url, String fileName) {
this.url = url;
this.fileName = fileName;
}
//下载图片线程的执行体
实现Callable接口
package com.aly.dxc;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* @author aly
* @version 1.0
* @date 2020/10/19 23:08
*/
//线程创建方式三:实现Callable接口
//好处:可以自定义返回值 可以抛出异常
public class Callable implements java.util.concurrent.Callable<Boolean> {
public String url;
public String fileName;
public Callable(String url, String fileName) {
this.url = url;
this.fileName = fileName;
}
//下载图片线程的执行体
