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

一、什么是线程?

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

多线程是什么?

  • 多条线程由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.rhkb.cn/news/354598.html

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

相关文章

机器人学习和研究的物质基础包含哪些内容?

为啥写这个&#xff1f; 在很多博客里面提及物质基础&#xff0c;没想到询问的也非常多&#xff0c;写一篇详细一点的。 之前的故事 不合格且失败机器人讲师个人理解的自身课程成本情况-CSDN博客 迷失自我无缘多彩世界-2024--CSDN博客 物质基础与情绪稳定的关系-CSDN博客 …

Javaweb登录校验

登录校验 JWT令牌的相关操作需要添加相关依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>一、摘要 场景&#xff1a;当我们想要访问一个网站时&am…

Vue开发中Element UI/Plus使用指南:常见问题(如Missing required prop: “value“)及中文全局组件配置解决方案

文章目录 一、vue中使用el-table的typeindex有时不显示序号Table 表格显示索引自定义索引报错信息解决方案 二、vue中Missing required prop: “value” 报错报错原因解决方案 三、el-table的索引值index在翻页的时候可以连续显示方法一方法二 四、vue3中Element Plus全局组件配…

VMware RedHat虚拟机磁盘扩容(添加磁盘和扩展磁盘)

前言 自己的电脑上配一个虚拟机还是很有必要的&#xff0c;用起来比双系统方便一点&#xff0c;之前搞了100g的ubuntu没用到&#xff0c;后面重装redhat觉得随便搞个20g就够用了&#xff0c;后面用到之后就遇到磁盘不够用的情况&#xff0c;只能说情况允许的话&#xff0c;磁盘…

CityEngine记录1:工程目录

CityEngine的工程目录结构对于理解和组织3D城市建模项目至关重要。以下是对CityEngine工程目录结构的详细解析&#xff1a; Assets&#xff1a; 存放模型的零件与纹理图片。这些资产通常用于在建模过程中为建筑物、道路、植被等元素添加详细的纹理和细节。 Data&#xff1a; …

自学鸿蒙HarmonyOS的ArkTS语言<一>基本语法

一、一个ArkTs的目录结构 二、一个页面的结构 A、装饰器 Entry 装饰器 : 标记组件为入口组件&#xff0c;一个页面由多个自定义组件组成&#xff0c;但是只能有一个组件被标记 Component : 自定义组件, 仅能装饰struct关键字声明的数据结构 State&#xff1a;组件中的状态变量…

图像处理:Python使用OpenCV进行图像锐化 (非锐化掩模、拉普拉斯滤波器)

文章目录 非锐化掩模 (Unsharp Masking)拉普拉斯滤波器 (Laplacian Filter)效果对比总结 在图像处理中&#xff0c;锐化操作用于增强图像的边缘和细节&#xff0c;使图像看起来更清晰。常见的图像锐化方法包括非锐化掩模&#xff08;Unsharp Masking&#xff09;和拉普拉斯滤波…

AI 音乐大模型:创新的曙光还是创意产业的阴影?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

[Kubernetes] etcd 单机和集群部署

文章目录 1.etcd基本概念2.etcd的基本知识3.etcd优势4.etcd单机部署4.1 linux部署4.2 windows部署4.3 docker安装etcd 5.etcd集群部署 1.etcd基本概念 etcd是一个高可用的分布式键值存储系统&#xff0c;是CoreOS&#xff08;现在隶属于Red Hat&#xff09;公司开发的一个开源…

人工智能这么厉害,比如GPT-4,为什么没有看到程序员大量失业?

从ChatGPT第一版发布到现在&#xff0c;还不到一年的时间中&#xff0c;可是它使用的GPT架构已经从3.5版本进化到现在的4.0版本&#xff0c;随之而来的是其能力的极大提升。下面是GPT-4在其官网的介绍中的一句话&#xff1a; GPT-4是OpenAI最先进的系统&#xff0c;可以产生更安…

数学建模基础:数学建模概述

目录 前言 一、数学建模的步骤 二、模型的分类 三、模型评价指标 四、常见的数学建模方法 实际案例&#xff1a;线性回归建模 步骤 1&#xff1a;导入数据 步骤 2&#xff1a;数据预处理 步骤 3&#xff1a;建立线性回归模型 步骤 4&#xff1a;模型验证 步骤 5&…

python-基础篇-文件和异常

文章目录 文件和异常读写文本文件读写二进制文件读写JSON文件 文件和异常 实际开发中常常会遇到对数据进行持久化操作的场景&#xff0c;而实现数据持久化最直接简单的方式就是将数据保存到文件中。说到“文件”这个词&#xff0c;可能需要先科普一下关于文件系统的知识&#…

渗透测试基础(四) MS08-067 漏洞攻击

1. 漏洞介绍 漏洞描述 Microsoft Windows Server服务RPC请求缓冲区溢出漏洞Windows的Server服务在处理特质RPC请求时存在缓冲区溢出漏洞&#xff0c;远程攻击者可以通过发送恶意的RPC请求触发这个溢出&#xff0c;导致完全入侵用户系统&#xff0c;以SYSTEM权限执行任意指令。…

C#使用Scoket实现服务器和客户端互发信息

20240616 By wdhuag 目录 前言&#xff1a; 参考&#xff1a; 一、服务器端&#xff1a; 1、服务器端口绑定&#xff1a; 2、服务器关闭&#xff1a; 二、客户端&#xff1a; 1、客户端连接&#xff1a; 2、客户端断开&#xff1a; 三、通讯&#xff1a; 1、接收信…

Python4 操作MySQL数据库

通过python的pymysql库连接到本地的MySQL数据库&#xff0c;并执行查询操作来获取数据&#xff0c;然后打印出每一行的数据&#xff0c;这里以一个简单的学生表为例进行介绍。 1. MySQL的安装与数据准备 首先需要安装MySQL&#xff0c;在安装完成之后使用Navicat与本地数据库…

1-函数极限与连续

1 2 平方项没有考虑到&#xff08;其正负&#xff09;

gitlab-cicd-k8s

k8s已经准备好 kubectl get node 创建cicdYaml文件 kubectl create namespace gitlab-cicd --dry-runclient --outputyaml >> gitlab-cicd.yaml kubectl apply -f gitlab-cicd.yaml 服务器和仓库在一起可用专有地址 使用 GitLab Runner 可以自动执行 GitLab CI/CD 管道…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第45课-使用头像

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第45课-使用头像 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎&…

zip文件上传到linux服务器文件大小发生变化

在传一个文件到服务器的时候&#xff0c;第一次传完看见大小不一样&#xff08;服务器中du命令查看大小796596MB&#xff09;就重传了一下&#xff0c;还是大小不一样&#xff0c;就查了下。 查了下有以下原因&#xff1a; 文件系统的不同&#xff1a; 原因&#xff1a;不同的…

boost asio异步服务器(3)增加发送队列实现全双工通信

增加发送节点 构造发送节点&#xff0c;管理发送数据。发送节点的类如下。 这个发送节点用于保证发送和接收数据的有效性。 增加发送队列 前边实现的是一个简单的echo服务器&#xff0c;也就是服务器将收到的内容发送给对应的客户端。但是在实际的服务器设计中&#xff0c;服务…