肖sir_Java 多线程___18
Java 多线程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,一个应用程序至少包含一个进程。
线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每条线程并行执行不同的任务,一个进程中至少包含一个线程
总结:
进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程—资源分
配的最小单位。
线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执
行流。线程—程序执行的最小单位。
1.2 线程介绍
一个线程的生命周期:
2.1 多线程介绍
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。
具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。
线程是系统对代码的执行进程,如果将系统当做一个员工,被安排执行某个任务的时候,他不会对任何其他的任务作出响应。只有当这个任务执行完毕,才可以重新给他
分配任务。每一个程序都有一个主线程,负责执行程序必要的任务。
多线程是指,将原本线性执行的任务分开成若干个子任务同步执行,这样做的优点是防止线程“堵塞”,增强用户体验和程序的效率。缺点是代码的复杂程度会大大提高,而且对于硬件的要求也相应地提高。
3.1 创建线程
Java中创建线程的方式:
1,通过实现 Runnable 接口。
2,通过继承 Thread 类本身。
Thread和Runnable的区别
实现Runnable接口比继承Thread类所具有的优势:
1,适合多个相同的程序代码的线程去处理同一个资源
2,可以避免java中的单继承的限制
3,增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4,线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
说明:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程
3.2 创建线程
通过实现 Runnable 接口来创建线程
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。
为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:
class RunnableDemo implements Runnable {
public void run(){
}
}
3.3 创建线程
通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个
该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才
能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一
个实例。
class ThreadDemo extends Thread {
public void run() {
}
public void start () {
}
}
3.4 创建线程
Thread常用实例方法
![](https://img2022.cnblogs.com/blog/2724103/202210/2724103-20221001120109404-1287989203.png)
3.5 创建线程
Thread常用静态方法
![](https://img2022.cnblogs.com/blog/2724103/202210/2724103-20221001120603260-399120140.png)
3.6 创建线程
多线程中几个主要概念:
线程同步
线程间通信
线程死锁
线程控制:挂起、停止和恢复
多线程的使用
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!
3.7 创建线程
线程同步:指当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址
进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线
程又处于等待状态。
在Java中,通过synchronized关键字进行同步的保证。
实现同步有两种方式:
1,同步代码块
synchronized(同步对象){
//
}
2,同步方法
void synchronized shareFunction(){
// 方法体
}
3.8 创建线程
同步代码块,实例:
public class RunnableImpl implements Runnable {
private List<String> lists = new ArrayList<>();
@Override
public void run() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
lists.add(i + "");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(lists.toString());
}
}
// 两个条线程同时往list中插入10条数据
// 测试类中的main方法:
public static void main(String[] args) {
RunnableImpl runnable1 = new RunnableImpl();
Thread thread1 = new Thread(runnable1,"线程一");
thread1.start();
Thread thread2 = new Thread(runnable1,"线程二");
thread2.start();
}
3.9 创建线程
同步方法,实例:
public class RunnableImpl implements Runnable {
private List<String> lists = new ArrayList<>();
@Override
public void run() {
this.listAdd();
}
public synchronized void listAdd() {
for (int i = 0; i < 10; i++) {
lists.add(i + "");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(lists.toString());
}
}
// 两个条线程同时往list中插入10条数据
// 测试类中的main方法:
public static void main(String[] args) {
RunnableImpl runnable1 = new RunnableImpl();
Thread thread1 = new Thread(runnable1,"线程一");
thread1.start();
Thread thread2 = new Thread(runnable1,"线程二");
thread2.start();
}
4.1 线程池
线程池的优势
1、降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
2、提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
3、方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换
4、提供更强大的功能,延时定时线程池。
线程池的主要参数
1、corePoolSize(线程池基本大小)
2、maximumPoolSize(线程池最大大小):线程池所允许的最大线程个数。
3、keepAliveTime(线程存活保持时间)
4、workQueue(任务队列):用于传输和保存等待执行任务的阻塞队列。
4.1 线程池 -线程池流程
![](https://img2022.cnblogs.com/blog/2724103/202210/2724103-20221001121840754-332075500.png)
课后练习题:
1,某银行卡账号上有500元现金,一个人拿着存折去柜台取钱,同时另一个人拿着卡去ATM上取钱,各自取400元。现要求取钱的过程中不能出现资源竞争,比如400元被取出2次。
2,使用两个线程操作同一个文件,一个对文件进行读操作,一个对文件进行写操作。
3,一个盘子中有30颗糖,两个小孩去盘子中抢糖,一次只抢一颗糖,当盘子中的糖被拿完后看两个小孩各抢了多少颗糖。请用java多线程来模拟孩子的抢糖过程并输出结果到控制台。