多线程(总结黑马程序员)

一、什么是线程?

  • 是一个程序内部的一条执行流程

多线程是什么?

  • 多条线程由CPU负责调度执行

多线程的创建方式一:继承Thread类

//1.继承Thread类
public class MyThread extends Thread {//2.必须重写run方法@Overridepublic void run() {for (int i = 1; i <= 5 ; i++) {System.out.println("子线程MyThread输出 :" + i);}}
}public class ThreadTest1 {//main方法是由一条默认的主线程负责执行public static void main(String[] args) {//3.创建MyThread线程类的对象代表一个线程Thread t = new MyThread();//4.启动线程(自动执行run方法)t.start();for (int i = 1; i <= 5 ; i++) {System.out.println("主线程main输出:" + i);}}
}

多线程的创建方式二:实现Runnable接口

//1.实现Runnable接口
public class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 1; i <= 5 ; i++) {System.out.println("子线程输出:" + i);}}
}public class ThreadTest1 {public static void main(String[] args) {Runnable target = new MyRunnable();new Thread(target).start();for (int i = 1; i <= 5 ; i++) {System.out.println("主线程main输出:" + i);}}
}

匿名内部类的写法

public class ThreadTest1 {public static void main(String[] args) {//直接创建Runnable接口的匿名内部类Runnable target = new MyRunnable(){@Overridepublic void run() {for (int i = 1; i <= 5 ; i++) {System.out.println("子线程1输出:" + i);}}};new Thread(target).start();//简化形式1:new Thread(new MyRunnable(){@Overridepublic void run() {for (int i = 1; i <= 5 ; i++) {System.out.println("子线程2输出:" + i);}}}).start();//简化形式2new Thread(() -> {for (int i = 1; i <= 5 ; i++) {System.out.println("子线程3

多线程的创建方式三:;利用Callable接口、FutureTask类来实现

//1.让这个类实现Callable接口
public class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}//2.重写call方法@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n ; i++) {sum += i;}return "线程求出了1-" + n + "的和是:" + sum;}
}public static void main(String[] args) throws ExecutionException, InterruptedException {//3.创建一个Callable对象Callable call = new MyCallable(100);//4.把Callable的对象封装成一个FutureTask对象//未来对象的作用?//1.是一个任务对象,实现了Runnable对象//2.可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后FutureTask<String> f1 = new FutureTask<>(call);new Thread(f1).start();Callable<String> call2 = new MyCallable(200);FutureTask<String> f2 = new FutureTask<>(call2);new Thread(f2).start();//6.获取线程执行完毕后返回的结果//注意:如果执行到这,假如上面的线程还没有执行完毕//这里的代码会暂停,等待上面线程执行完毕后才会获取结果String rs = f1.get();System.out.println(rs);String rs2 = f2.get();System.out.println(rs2 );}

Thread常用方法

public class ThreadTest1 {public static void main(String[] args) {MyThread t1 = new MyThread("1号线程");t1.start();System.out.println(t1.getName());MyThread t2 = new MyThread("2号线程");t2.start();System.out.println(t2.getName());//主线程对象的名字//哪个线程执行它,它就会得到哪个线程对象Thread m = Thread.currentThread();m.setName("最diao的线程");System.out.println(m.getName());for (int i = 1; i <= 5 ; i++) {System.out.println(m.getName() + "线程输出:" + i);}}
}public class MyThread extends Thread {public MyThread(String name) {super(name); //为当前线程设置名字}@Overridepublic void run() {Thread t = Thread.currentThread();for (int i = 1; i <= 3 ; i++) {System.out.println();}}
}

二、线程安全问题 

出现原因:

  • 存在多个线程同时执行
  • 同时访问一个共享资源
  • 存在修改该共享资源

取钱案例

需求:小明和小红有一个共同的账户,余额是10万元,模拟2人同时去取钱10万

  • 测试类
public class ThreadTest {public static void main(String[] args) {//1.创建一个账户对象,代表两个人的共享账户Account acc = new Account("ICBC-110", 100000);//2.创建两个线程,分别代表小明 小红,再去同一个账户对象中取钱10万new DrawThread(acc,"小明").start();new DrawThread(acc,"小红").start();}
}
  • 线程类
public class DrawThread extends Thread{private  Account acc;public DrawThread(Account acc,String name) {super(name);this.acc = acc;}@Overridepublic void run() {//取钱acc.drawMoney(100000);}
}
  • 账户类
public class Account {private String cardId; //卡后private double money;  //账户余额public Account() {}public void drawMoney(double money) {//先搞清楚是谁来取钱String name = Thread.currentThread().getName();//1.判断余额是否够if(this.money >= money){System.out.println(name + "来取钱" + money + "成功!");this.money -= money;System.out.println(name + "取钱后,剩余余额:" + this.money);}else{System.out.println(name + "来取钱,余额不足");}}public Account(String cardId, double money) {this.cardId = cardId;this.money = money;}public String getCardId() {return cardId;}public void setCardId(String cardId) {this.cardId = cardId;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}}

三、线程同步

  • 解决线程安全问题的方案

线程同步的思想

  • 让多个线程实现先后依次访问共享资源

常见方案

  • 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来

方式1:同步代码块

  • 作用:把访问共享资源的核心代码给上锁,保证线程安全
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
public void drawMoney(double money) {//先搞清楚是谁来取钱String name = Thread.currentThread().getName();//1.判断余额是否够//this代表共享资源synchronized (this) {if(this.money >= money){System.out.println(name + "来取钱" + money + "成功!");this.money -= money;System.out.println(name + "取钱后,剩余余额:" + this.money);}else{System.out.println(name + "来取钱,余额不足");}}}

方式2:同步方法

  • 作用:把访问共享资源的核心方法给上锁
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
 public synchronized void drawMoney(double money) {}

同步方法底层原理 

  • 如果方法是实例方法:默认用this作为锁的对象
  • 如果方法是静态方法:默认用类名.class作为锁的对象

是同步代码块好还是同步方法好?

  • 范围上:同步代码块锁的范围更小,同步方法锁的范围更大
  • 可读性:同步方法更好

方式3:Lock锁

  • Lock锁是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象
 //创建了一个锁对象private final Lock lk = new ReentrantLock();public void drawMoney(double money) {//先搞清楚是谁来取钱String name = Thread.currentThread().getName();try {lk.lock(); //加锁if(this.money >= money){System.out.println(name + "来取钱" + money + "成功!");this.money -= money;System.out.println(name + "取钱后,剩余余额:" + this.money);}else{System.out.println(name + "来取钱,余额不足");}} catch (Exception e) {e.printStackTrace();} finally {lk.unlock();//解锁}}

四、线程池

什么是线程池?

  • 一个可以复用线程的技术

不使用线程池的原因

  • 创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,严重影响系统的性能

谁代表线程池?

  • 代表线程池的接口:ExEcuatorService

如何得到线程池对象?

 

  • 方式1:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
public class ThreadPoolTest {public static void main(String[] args) {
//        public ThreadPoolExecutor(int corePoolSize,
//                                    int maximumPoolSize,
//                                    long keepAliveTime,
//                                    TimeUnit unit,
//                                    BlockingQueue<Runnable> workQueue,
//                                    ThreadFactory threadFactory,
//                                    RejectedExecutionHandler handler) {//1.创建一个线程池对象ExecutorService pool =   new ThreadPoolExecutor(3,5,8,TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}
}

   //2.使用线程池处理Callable任务Future<String> f1 = pool.submit(new MyCallable(100));Future<String> f2 = pool.submit(new MyCallable(200));Future<String> f3 = pool.submit(new MyCallable(300));Future<String> f4 = pool.submit(new MyCallable(400));System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());

 Executors工具类实现线程池

 //1-2 通过Executors创建线程池对象ExecutorService pool = Executors.newFixedThreadPool(3);//核心线程数量到底配置多少呢?//计算密集型的任务:核心线程数量 = CPU的核数 + 1//IO密集型的任务:核心线程数量 = CPU的核数 + 2

五、线程的并发、并行和生命周期

进程

  • 正在运行的程序就是一个独立的进程
  • 进程中的多个线程其实是并发并行执行的

并发的含义

  • 进程中的线程是由CPU调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能执行,CPU会轮询为系统的每个线程服务

并行的理解

  • 在同一个时刻,同时有多个线程在被CPU调度

线程的生命周期

  • 也就是线程从生到死的过程,经历的各种状态及状态转换

JAVA线程的状态

  • 总共定义6种状态
  • 都定义在Thread类的内部枚举类中
public enum State {/*** Thread state for a thread which has not yet started.*/NEW,/*** Thread state for a runnable thread.  A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.*/RUNNABLE,/*** Thread state for a thread blocked waiting for a monitor lock.* A thread in the blocked state is waiting for a monitor lock* to enter a synchronized block/method or* reenter a synchronized block/method after calling* {@link Object#wait() Object.wait}.*/BLOCKED,/*** Thread state for a waiting thread.* A thread is in the waiting state due to calling one of the* following methods:* <ul>*   <li>{@link Object#wait() Object.wait} with no timeout</li>*   <li>{@link #join() Thread.join} with no timeout</li>*   <li>{@link LockSupport#park() LockSupport.park}</li>* </ul>** <p>A thread in the waiting state is waiting for another thread to* perform a particular action.** For example, a thread that has called {@code Object.wait()}* on an object is waiting for another thread to call* {@code Object.notify()} or {@code Object.notifyAll()} on* that object. A thread that has called {@code Thread.join()}* is waiting for a specified thread to terminate.*/WAITING,/*** Thread state for a waiting thread with a specified waiting time.* A thread is in the timed waiting state due to calling one of* the following methods with a specified positive waiting time:* <ul>*   <li>{@link #sleep Thread.sleep}</li>*   <li>{@link Object#wait(long) Object.wait} with timeout</li>*   <li>{@link #join(long) Thread.join} with timeout</li>*   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>*   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>* </ul>*/TIMED_WAITING,/*** Thread state for a terminated thread.* The thread has completed execution.*/TERMINATED;}

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

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

相关文章

【数据结构】【版本1.3】【线性时代】——栈

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、栈的概念二、栈的模拟实现2.1 定义2.2 初始化2.3 销毁2.4 压栈2.5 判空2.6 出栈2.7 获取栈顶元素2.8…

RAG优化技巧|7大挑战与解決方式|提高你的LLM能力

在当今快速发展的人工智能领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;已经成为无处不在的技术&#xff0c;它们不仅改变了我们与机器交流的方式&#xff0c;还在各行各业中发挥着革命性的影响。 然而&#xff0c;尽管LLM RAG的能力已经让人惊叹&#xff0c;但我…

浅谈配置元件之JDBC连接配置

浅谈配置元件之JDBC连接配置 通过使用“JDBC连接配置”配置元件&#xff08;JDBC Connection Configuration&#xff09;&#xff0c;您可以轻松地在JMeter测试计划中集成数据库交互能力。本指南将详细介绍如何设置和使用此配置元件来连接数据库并执行SQL查询。 1. 准备工作 …

微服务架构:解构现代应用程序的未来

目录 前言1. 微服务架构的基本概念1.1 什么是微服务架构1.2 微服务与单体架构的对比 2. 微服务架构的优势2.1 灵活性与可扩展性2.2 持续交付与部署2.3 技术多样性2.4 故障隔离 3. 微服务架构的挑战3.1 服务间通信和数据一致性3.2 运维复杂度3.3 安全性3.4 开发团队的协作 4. 微…

手机铃声下载2个必备技巧,定制化铃声,彰显个性魅力

手机铃声&#xff0c;就像是独特的信号灯&#xff0c;不仅仅是通知我们来电或信息的方式&#xff0c;更是展现个人品位和魅力的武器。手机铃声下载和定制&#xff0c;让你的手机从千万舰队中脱颖而出。在接下来的文章中&#xff0c;我们将详细探讨铃声下载技巧的具体操作步骤&a…

2024人工智能指数报告(二):技术性能

背景 从2017年开始&#xff0c;斯坦福大学人工智能研究所&#xff08;HAI&#xff09;每年都会发布一份人工智能的研究报告&#xff0c;人工智能指数报告&#xff08;AII&#xff09;&#xff0c;对上一年人工智能相关的数据进行跟踪、整理、提炼并进行可视化。这份指数报告被认…

深度学习1 -- 开头

一 前言 感觉用这玩意越来越多&#xff0c;所以想学学。不过没想好怎么学&#xff0c;也没有提纲&#xff0c;买了两本书&#xff0c;一本是深度学习入门&#xff0c;小日子写的。还有一本就是花书。还有就是回Gatech参加线上课程&#xff0c;CS7643。 CS 7643: Deep Learnin…

【stm32-新建工程-寄存器版本】

stm32-新建工程-寄存器版本 ■ 下载相关STM32Cube官方固件包&#xff08;F1&#xff0c;F4&#xff0c;F7&#xff0c;H7&#xff09;■ 1. ST官方搜索STM32Cube■ 2. 搜索 STM32Cube■ 3. 点击获取软件■ 4. 选择对应的版本下载■ 5. 输入账号信息■ 6. 出现下载弹框&#xff…

推荐 2 个 牛哔哄哄 的 GitHub 项目

推荐两个开源的 GitHub 项目&#xff0c;一个基于大模型的企业级知识库问答系统&#xff0c;支持管理企业知识库、对话问答、RAG 等功能。 另外一个是计算机视觉的工具箱&#xff0c;使用它你可以在你电脑上实现人体跟踪、分割、检测等一系列计算机视觉的场景。 01 基于 LLM 大…

【unity笔记】二、海洋系统Crest Ocean System插件使用

一、介绍 Crest 是 Unity 技术先进的海洋系统。 它专为性能而设计&#xff0c;并大量使用细节级别 &#xff08;LOD&#xff09; 策略和 GPU 加速来实现快速更新和渲染。它还具有高度的灵活性&#xff0c;允许对水形状/泡沫/动态波浪/等进行任何自定义输入&#xff0c;并具有直…

01 基础入门 编写你的第一个 Go 语言程序

从这节课开始&#xff0c;我会带你走进 Go 语言的世界。我会用通俗易懂的语言&#xff0c;介绍 Go 语言的各个知识点&#xff0c;让你可以从零开始逐步学习&#xff0c;再深入它的世界。不管你以前是否接触过 Go 语言&#xff0c;都可以从这个专栏中受益。 现在&#xff0c;让…

时隔一年,SSD大涨价?

同样产品&#xff0c;2T&#xff0c;去年400多到手&#xff0c;今年700。 去年 今年

3ds Max软件下载安装:3D建模软件 轻松开启你的建模之旅!

3ds Max&#xff0c;在建模过程中&#xff0c;网格建模和NURBS建模两大技术发挥着不可或缺的作用。网格建模允许用户通过顶点、边和面等元素的调整&#xff0c;精确地塑造出模型的形态&#xff1b;而NURBS建模则以其优秀的曲线和曲面处理能力&#xff0c;为设计师们提供了更为平…

迅为RK3568驱动教程第十八期-PWM

系统性PWM课程&#xff0c;完全掌握PWM。采用框架学习法&#xff0c;从基础知识、PWM子系统框架、API函数理论由面到点&#xff0c;逐个击破。通过SG90舵机&#xff0c;呼吸灯的控制把理论转为动手能力。最后从零实现输入捕获驱动程序&#xff0c;深入探究&#xff0c;体验一把…

《人工智能导论》书面作业

第 1 章&#xff1a;绪论 1、分别解释人工智能的三个主要学派的代表人物和主要思想&#xff0c;并给出每个学派的一个实际应用实例。 符号主义&#xff08;Symbolists 或 逻辑主义&#xff09;&#xff1a; 代表人物&#xff1a;马文闵斯基&#xff08;Marvin Minsky&#xf…

人工智能大模型之开源大语言模型汇总(国内外开源项目模型汇总)

开源大语言模型完整列表 Large Language Model (LLM) 即大规模语言模型&#xff0c;是一种基于深度学习的自然语言处理模型&#xff0c;它能够学习到自然语言的语法和语义&#xff0c;从而可以生成人类可读的文本。 所谓"语言模型"&#xff0c;就是只用来处理语言文…

一文带你理清同源和跨域

1、概述 前后端数据交互经常会碰到请求跨域&#xff0c;什么是跨域&#xff0c;为什么需要跨域&#xff0c;以及常用有哪几种跨域方式&#xff0c;这是本文要探讨的内容。 同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。同源策略限制了从同一个源加载的…

SN74HC14+陶瓷振子做振荡器的试验初步

面包板搭建&#xff0c;4.5V电池供电。 注意我用杜邦线插1脚并缠绕到小频谱的天线上面&#xff0c;如果直接用杜邦线转sma。请先过衰减器。 本想试验一下465khz用SN74HC14做振荡器&#xff0c;实验了很多次&#xff0c;无法起振。 用1M&#xff0c;4M的也无法起振&#xff0c;…

JavaSE 面向对象程序设计 正则表达式

正则表达式 正则表达式&#xff08;Regular Expression&#xff0c;简称Regex&#xff09;是用于匹配文本中模式的字符串表达式。它由普通字符&#xff08;例如字母、数字&#xff09;和特殊字符&#xff08;称为元字符&#xff09;组成&#xff0c;可以非常灵活地定义搜索模式…

[问题记录]Qt QGraphicsItem 移动时出现残影

目录 1.问题现象 2.问题原因 3.修改方案 1.问题现象 自定义 QGraphicsItem 时&#xff0c;绘制rect&#xff0c;对象移动时出现残影。 2.问题原因 直接原因是view未刷新的问题&#xff0c;所以网上有人使用方案 setViewportUpdateMode(QGraphicsView::FullViewportUpdate…