多线程基础篇

我们平常说的一个程序,一个程序中有声音,图片,字幕
实际上是一个进程中有多个线程

main线程是主线程。
多核,多个cpu,多个线程,切换的很快
单核的话是一个cpu,某一时间只能是一个线程,但是因为切换的很快, 因此有同时执行的错觉。

在一个进程中,如果开辟了多个线程,线程的运行是由调度器安排调度,调度器与操作系统紧密相关,先后顺序是不能认为干预的。
对同一份资源操作,会存在资源抢夺的问题,需要加入并发控制。
线程会带来额外的开销,cpu调度,线程的切换等

每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。ThreadLocal

创建线程的三种方式

1、继承thread类
2、实现Runnable接口
3、实现Callable接口

继承Thread类,重写run方法,调用start方法执行

在这里插入图片描述

实现Runnable接口,重写run方法,调用start方法执行

需要创建runnable接口的实现类对象,然后创建线程对象,通过线程对象开启线程,代理
在这里插入图片描述java是单继承,我们一般使用runnable接口创建线程。

在这里插入图片描述
这里我们可以看到一个对象可以被多个线程使用,换句话说就是多个线程会使用同一个资源,那么这里就会涉及到并发问题->线程安全问题->数据紊乱

实现Callable接口

在这里插入图片描述这里的创建服务的是一个池子。有几个线程,nThread就是多少
submit是提交执行线程。
在这里插入图片描述

Thread的常用方法

Thread currentThread()   //获取当前线程
Thread.currentThread().getName() //获取当前线程的名称 
setPriority(int newPriority)  //更改线程的优先级
getPriority()  //获取线程优先级
static void sleep(long millis) //休眠
static void yield()//当前线程对象暂停执行,执行其他线程,一直到其他线程执行完继续执行当前线程
void join() //插队相当于vip
void interrupt() //中断线程
boolean isAlive() //判断线程的是否存活
Thread.State getState()//获取线程的状态
setDaemon(true)  // 设置线程为守护线程

yield礼让线程,从运行状态转换为就绪状态,重新竞争资源,礼让不一定成功
join 霸道线程,直接插队,其他执行线程变成阻塞状态

如何优雅的暂停线程

stop/destroy是不推荐的
1、一般是通过一个标志位进行终止变量,flag=false
2、推荐线程自己停止,利用次数,不建议死循环

代理模式

静态代理:

前提:代理对象和目标对象要实现同一个接口。
就是代理对象中有目标对象,在代理对象的类中有一个方法调用了目标对象的方法。在实际使用的时候,实例化到了目标对象到代理对象中,然后代理对象调用方法。
好处:代理对象帮助目标对象做做不到的事情,目标对象只需要做自己的事情

动态代理

线程的状态

在这里插入图片描述
创建状态—new Thread()
就绪状态–start()
等待cpu调度,调度了就会运行–运行状态–线程执行线程体的代码块
阻塞状态—运行中的线程sleep了,也就是说cpu被抢夺
只有当阻塞状态接触,会重新进入就绪状态,等待cpu的调度。

Thread.State

在这里插入图片描述
NEW :新生状态
RUNNABLE :运行状态
BLOCKED :阻塞状态
WAITING:等待
TIME_WAITING:
TERMINATED:死亡
死亡后的线程不能再次启动。会报错的

线程的优先级

线程调度器是根据优先级来调度线程的,优先级高的最先被调度,同级的随机调度。
线程优先级用数字表示,范围是1-10

在这里插入图片描述

守护线程daemon

线程氛围用户线程和守护线程
虚拟机必须确保用户线程(main)执行完毕,虚拟机不用等待守护线程(gc)执行完毕。
比如后台记录日志,监控内存,垃圾回收等等都是守护线程。
当主线程运行完毕,虚拟机就关闭了,即使守护线程还在运行。

线程同步

线程同步其实就是一种等待机制,多个线程竞争这个资源的时候,会有一个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程再使用。

队列和锁synochronized

线程同步需要队列和锁,每个对象都有一把锁,这样才能保证线程的安全性。

由于同一个进程的多个线程共享同一块存储空间,有数据的一个共享,因此会带来线程不安全和并发的问题,为了保证数据在方法中被访问时的正确性,我们在访问的时候加入锁机制synchronized,当一个线程获得对象的排它锁,就会独占资源,其他线程必须等待,当该线程使用完毕后会释放锁。
但可能会出现以下问题:在这里插入图片描述同步方法
public synchronized void method(int args){}
这个方法控制对对象的访问,每个对象都有一把锁,synchronized关键字是当访问这个方法的时候必须要获取对象的锁之后才可以访问。
弊端:锁住了整个方法,耗费资源
同步块
当方法里面有需要修改的内容才需要锁,因此出现了同步代码块

但是需要注意的是:synchronized是获取的当前对象的锁,默认锁的是this本身。因此我们需要使用同步块,同步块是同步监视器,可以监视任意对象,换句话说,锁的是共享资源。
在这里插入图片描述比如银行取钱,锁的应该是账户,多个线程访问账户的时候,都应该按照队列进行。因此我们需要使用的是同步代码快。
换句话说,锁的对象是变化的,需要增删改的对象。
synchronized是一个隐式锁,我们不知道他何时

JUC–线程安全集合CopyOnWriteArrayList

这个集合是java.util.concurrent包下的,java并发包下的
Arraylist是线程不安全的。
CopyOnWriteArrayList是线程安全的,不需要我们手动加锁。

死锁

Lock锁

从jdk5.0开始,jdk就提供了一个更强大的线程同步机制:通过显示定义同步锁对象来实现同步—Lock锁。
他是java.util.concurrent包下的,它拥有与synchronized相同的并发性和内存语义,可以显示加锁,释放锁。常用的有ReetrantLock锁(可重用锁)。
手动加锁,解锁
在这里插入图片描述简单应用:
加一个属性是ReetrantLock lock,
在run方法中手动加锁 lock.lock
手动释放锁:lock.unlock();

sycnchronized和lock的对比

1、lock是显式锁,需要手动加锁释放锁,synchronized是隐式锁,出了作用域就自动释放。
2、lock只有代码块锁,而synchronized有方法锁和代码块锁。
3、使用lock锁比使用synchronized锁的性能更好,有更好的扩展性
优先使用顺序
Lock>同步代码快>同步方法
在这里插入图片描述

线程通信

这个是线程同步的问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。
对于生产者,没有生产产品之前,要通知消费者等待,生产产品之后要通知消费者消费。
对于消费者,在消费之后,要通知生产者已经结束消费,仍然需要产品消费。

在这里,synchronized是不同解决这个问题的,因为synchronized是锁住了共享资源,也就是变化的对象,只能保证对象的安全性,实现了同步,但是无法实现不同线程的消息传递。

解决方案:

通知 notify()
等待 wait()
在这里插入图片描述
在这里插入图片描述生产者–线程
消费者–线程
产品–普通类
缓冲池–普通类–有容器(集合或者数组)

使用线程池

在并发情况下,经常创建销毁线程对性能的影响很大。
因此我们选择使用线程池,提前创建好线程,放入线程池中,使用的时候直接获取,使用完后放回池中,实现重复利用。

优点:
1、提高响应速度
2、降低资源消耗
3、方便管理
线程池的大小corePoolSize
最大线程数maxinumPoolSize
线程没有任务时多久会终止keepAliveTime
线程池相关API:ExcutorService和Executors
ExecutorService:线程池接口。

常见子类:ThreadPoolExcutor
void  execute(Runnable command):执行任务,没有返回值,执行线程
<T>Future<T> submit(Callable<T> task):执行任务,有返回值,一般用来执行Callable
void shutdown()关闭连接池

Executors:线程池工具类,用于常见返回不同类型的线程池
Executors.newFixedThreadPool(int nThread)创建线程池,返回的是ExcutorService,参数nThread为线程池大小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/87363.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

法律小程序开发:让法律咨询更便捷

在现代社会&#xff0c;法律咨询服务越来越受到人们的重视和需求。为了方便用户预约法律咨询&#xff0c;很多律所都开始使用小程序来提供在线预约服务。那么&#xff0c;如何制作一款律所预约小程序呢&#xff1f; 首先&#xff0c;我们可以选择乔拓云网作为制作小程序的平台。…

Linux枚举文件目录、获取文件属性

目录 1.枚举指定路径下的文件目录2.获取文件属性stat其他方式&#xff1a;Linux获取文件属性stat()、fstat()、lstat()函数实现stat属性代码 1.枚举指定路径下的文件目录 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.…

【算法专题突破】双指针 - 盛最多水的容器(4)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;11. 盛最多水的容器 - 力扣&#xff08;Leetcode&#xff09; 这道题目也不难理解&#xff0c; 两边的柱子的盛水量是根据短的那边的柱子决定的&#xff0c; 而盛水量…

ubuntu22安装和部署Kettle8.2

前提 kettle是纯java编写的etl开源工具&#xff0c;目前kettle7和kettle8都需要java8或者以上才能正常运行。所以运行kettle前先检查java环境是否正确配置&#xff0c;java版本是否是8或者以上。 kettle安装 1、创建kettle目录&#xff0c;并将kettle的zip包解压到kettle目…

MySQL - 表空间碎片整理方法

MySQL数据库中的表在进行了多次delete、update和insert后&#xff0c;表空间会出现碎片。定期进行表空间整理&#xff0c;消除碎片可以提高访问表空间的性能。 检查表空间碎片 下面这个实验用于验证进行表空间整理后对性能的影响&#xff0c;首先检查这个有100万记录表的大小&…

【业务功能篇86】微服务-springcloud-系统性能压力测试-jmeter-性能优化-JVM参数调优

系统性能压力测试 一、压力测试 压力测试是给软件不断加压&#xff0c;强制其在极限的情况下运行&#xff0c;观察它可以运行到何种程度&#xff0c;从而发现性能缺陷&#xff0c;是通过搭建与实际环境相似的测试环境&#xff0c;通过测试程序在同一时间内或某一段时间内&…

【最强最全】视频号下载助手(支持视频号视频, 直播,回放下载)

视频号下载助手支持视频号视频, 直播,回放的下载&#xff0c;本工具基于秦天sunny中间件编写&#xff0c;无需再使用其它抓包软件&#xff0c;无需再使用其它下载软件。 当然&#xff0c;你也可以右键复制抓取后的视频源再用其它下载软件下载。 使用说明 解压文件&#xff0c;…

Matlab(结构化程式和自定义函数)

目录 1.脚本编辑器 2.脚本流 2.1 控制流 2.2 关系&#xff08;逻辑&#xff09;操作符 3.脚本与函数 1.脚本编辑器 Matlab的命名规则&#xff1a; 常用功能&#xff1a; 智能缩进&#xff1a; 在写代码的时候&#xff0c;有的时候代码看起来并不是那么美观&#xff08;可读性…

华为云Stack的学习(二)

三、华为云Stack产品组件 FunsionSphere CPS 提供云平台的基础管理和业务资源&#xff08;包括计算资源和存储资源&#xff09;。采用物理服务器方式部署在管理节点。可以做集群的配置&#xff0c;扩容和运维管理。 Service OM 提供云服务的运维能力&#xff0c;采用虚拟化方…

【数据结构大全】你想要的都有,数组、链表、堆栈、二叉树、红黑树、B树、图......

目录 1.概述 2.线性结构 3.时间复杂度 4.查找算法 5.树 6.图 1.概述 博主之前写过一个完整的关于数据结构的系列文章&#xff0c;一共十三篇&#xff0c;内容包含&#xff0c;数组、链表、堆栈、队列、时间复杂度、顺序查找、二分查找、二叉树、二叉搜索树、平衡二叉树、…

LeetCode-406-根据身高重建队列

题目描述&#xff1a; 假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 正好 有 ki 个身高大于或等于 hi 的人。 请你重新构造…

设计模式(一)

1、适配器模式 &#xff08;1&#xff09;概述 适配器中有一个适配器包装类Adapter&#xff0c;其包装的对象为适配者Adaptee&#xff0c;适配器作用就是将客户端请求转化为调用适配者中的接口&#xff1b;当调用适配器中的方法时&#xff0c;适配器内部会调用适配者类的方法…