Java基础(四)

前言:本博客主要涉及java编程中的线程、多线程、生成者消费者模型、死锁。

目录

线程多线程

线程同步

synchronized

Lock锁

线程通信

生产者消费者模型

线程池

使用线程池处理Runnable任务

使用线程池处理Callable任务

Excutors

悲观锁

乐观锁

并发VS并行

线程的生命周期


线程多线程

创建一个简单的线程

获取执行当前代码的线程名:Thread.currentThread().getName()

开启线程:对象名.start()

守护线程 优先级

//1.创建一个继承于Thread类的子类
class MyThread extends Thread {//2.重写Thread类的run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);}}
}public class ThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();}
}
package learn12;class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 1; i <= 5; i++) {System.out.println("子线程输出:" + i);}}
}public class MyThreadTest2 {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);}}}

线程安全

例子:多个人同时去一个账户里取钱,被取出后,不能再取出钱。但多个线程执行时,在访问时,账户里有钱的,但实际上已经被其他用户取走,此时再取钱就会引发数据不安全的问题。

使用多线程时,每个线程都对数据进行修改,如何来保证数据的安全性?

package learn12;public class Account {private String cardId;private double money;public Account() {}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;}public void drawMoney(double money) {String name = Thread.currentThread().getName();if (this.money >= money) {System.out.println(name + "来取钱" + money + "成功!");this.money -= money;System.out.println(name + "来取钱,此时剩余:" + this.money);} else {System.out.println(name + "来取钱,但余额不足");}}
}
package learn12;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);}
}
package learn12;public class ThreadTest {public static void main(String[] args) {Account acc = new Account("ICBC-100", 100000);new DrawThread(acc, "小明").start();new DrawThread(acc, "小红").start();new DrawThread(acc, "小李").start();}
}

线程同步

使用了加锁的机制

synchronized

用到了同步控制关键字synchronized

用其修饰成员方法,被修饰的方法,在同一时间,只能被一个线程执行

//同步方法
public synchronized void drawMoney(double money) {String name = Thread.currentThread().getName();
//同步代码块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 + "来取钱,但余额不足");}}}

Lock锁

注意:解锁要放在finally里,以便程序出错时,可以解锁。

package learn12;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Account {private String cardId;private double money;//创建Lock锁对象private final Lock lk = new ReentrantLock();public Account() {}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;}public void drawMoney(double money) {String name = Thread.currentThread().getName();//加锁lk.lock();try {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();}}
}

线程通信

生产者线程负责生产数据

消费者线程负责消费生产者产生的数据

生产者消费者模型

package learn12;import java.util.ArrayList;
import java.util.List;public class Desk {private List<String> list = new ArrayList<>();public synchronized void put() {try {String name = Thread.currentThread().getName();if (list.size() == 0) {list.add(name + "做的肉包子");System.out.println(name + "做了一个肉包子");Thread.sleep(2000);//唤醒别人 等待自己this.notifyAll();this.wait();} else {//唤醒别人 等待自己this.notifyAll();this.wait();}} catch (InterruptedException e) {e.printStackTrace();}}public synchronized void get() {try {String name = Thread.currentThread().getName();if (list.size() == 1) {System.out.println(name + "吃了:" + list.get(0));list.clear();Thread.sleep(1000);//唤醒别人 等待自己this.notifyAll();this.wait();} else {//唤醒别人 等待自己this.notifyAll();this.wait();}} catch (InterruptedException e) {e.printStackTrace();}}
}
package learn12;public class ThreadTest4 {public static void main(String[] args) {Desk desk = new Desk();//生产者线程new Thread(() -> {while (true) {desk.put();}}, "厨师1").start();new Thread(() -> {while (true) {desk.put();}}, "厨师2").start();new Thread(() -> {while (true) {desk.put();}}, "厨师3").start();//消费者线程new Thread(() -> {while (true) {desk.get();}}, "吃货1").start();new Thread(() -> {while (true) {desk.get();}}, "吃货2").start();}
}

线程池

线程池就是一个可以复用线程的技术。

使用线程池的必要性:

用户发起一个请求,后台就需要创建一个新线程。不使用线程池,会产生大量的线程,会损害系统的性能。

线程池可以固定线程和执行任务的数量,可以避免系统瘫痪和线程耗尽的风险。

创建线程池

临时线程什么时候创建?

新任务提交时,发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时会创建临时线程。

什么时候可以拒绝新任务?

核心线程和临时线程都在忙,任务队列都满了,新的任务过来时才会开始拒绝任务。

使用线程池处理Runnable任务

package learn12;public class MyRunnableLearn implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "==>输出666");try {Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}}
}
package learn12;import java.util.concurrent.*;public class ThreadPoolTest {public static void main(String[] args) {//创建线程池对象
//        new ThreadPoolExecutor(
//                                int corePoolSize,
//                                int maximumPoolSize,
//                                long keepAliveTime,
//                                TimeUnit unit,
//                                BlockingQueue<Runnable> workQueue,
//                                ThreadFactory threadFactory,
//                                RejectedExecutionHandler handler
//        )ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());Runnable target = new MyRunnableLearn();pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);//都满了 拒绝新任务pool.execute(target);
//        pool.shutdownNow();//pool.shutdown();}
}

使用线程池处理Callable任务

package learn12;import java.util.concurrent.Callable;public class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return Thread.currentThread().getName() + "求出了1-" + n + "的和是:" + sum;}
}
package learn12;import java.util.concurrent.*;public class ThreadPoolTest2 {public static void main(String[] args) throws Exception {ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());//使用线程池处理Callbable任务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());}
}

 

Excutors

大型并发系统环境中使用Excutors如果不注意可能会出现系统风险。

核心线程数

计算密集型任务:核心线程数量 = CPU核数+1

IO密集型任务:核心线程数量 = CPU核数*2

package learn12;import java.util.concurrent.*;public class ThreadPoolTest2 {public static void main(String[] args) throws Exception {//通过Executors创建一个线程池对象ExecutorService pool = Executors.newFixedThreadPool(3);Executors.newSingleThreadExecutor();//使用线程池处理Callbable任务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());}
}

悲观锁

一开始就加锁,每次只能一个线程进入访问完毕后,再解锁,线程安全,性能较差。

package learn12;public class MyRunnable implements Runnable {public int count;@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(this);synchronized (this) {System.out.println("count ===>" + (++count));}}}
}

 

package learn12;public class Test {public static void main(String[] args) {Runnable target = new MyRunnable();for (int i = 1; i <= 100; i++) {new Thread(target).start();}}
}

乐观锁

一开始不上锁,等要出现线程安全问题时,等要出现线程安全问题时,线程安全,性能较好。

如何实现乐观锁

private AtomicInteger count = new AtomicInteger();
package learn12;import java.util.concurrent.atomic.AtomicInteger;public class MyRunnable implements Runnable {private AtomicInteger count = new AtomicInteger();@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(this);synchronized (this) {System.out.println("count ===>" + count.incrementAndGet());}}}
}

并发VS并行

python进阶学习也涉及到这里的知识点。

Python进阶(二)-CSDN博客

进程:正在运行的程序

线程:一个进程中可以运行多个线程

并发:线程是由CPU调度执行的,但CPU能同时处理的线程数量有限,为了保证全部线程都能执行,CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,好像是线程在同时执行,这就是并发。

并行:同一时间点,任务同时地运行,比如一台电脑,有8个CPU,每个CPU的每个核心都可以独立地执行一个任务,在同一时间点,可同时执行8个任务,这时任务是同时执行,并行地运行任务。

线程的生命周期

New:新建

Runnable:可运行

Timinated:被终止

Timed Waiting:计时等待

Waiting:无线等待

Blocked:阻塞

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

迅为iTOP-RK3568开发板Sobel 算子边缘检测

本小节代码在配套资料“iTOP-3568 开发板\03_【iTOP-RK3568 开发板】指南教程 \04_OpenCV 开发配套资料\32”目录下&#xff0c;如下图所示&#xff1a; Sobel (索贝尔)算子是计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检…

3D目标检测实战 | 图解KITTI数据集与数据格式

目录 1 数据集简介2 传感器坐标系3 数据集下载与组织4 数据内容说明4.1 矫正文件calib4.2 图像文件image4.3 点云文件velodyne4.4 标签文件label4.5 平面文件plane 1 数据集简介 KITTI数据集是一个广泛应用于自动驾驶和计算机视觉领域的公开数据集。该数据集由德国卡尔斯鲁厄理…

【Vue】ElementUI实现登录注册

目录 一.跨域的概述 1.1.概述 1.2.特点 二.ElementUI 2.1. 导入 2.2.搭建 2.3.页面 三.数据交互 3.1.安装相关模块 3.1.1安装模块 3.1.2查看模块 3.1.3.引用模块 3.2. axios的get请求 3.3. axios的post请求 四.注册功能 好啦今天到这了&#xff0c;希望能帮到你&…

unity gb28181 rtsp 视频孪生图像拉流和矫正插件(一)

目的是为了视频孪生&#xff0c;将视频放到三维里面&#xff0c;如果使用自己写的插件&#xff0c;有更好的灵活性&#xff0c;同时断线重连等等都更好控制了。 1、矫正算法和硬件解码 最好使用opencv制作&#xff0c;可以使用opencv的cuda加速&#xff0c;opencv的编译&…

Redis 缓存雪崩、缓存穿透、缓存击穿

Redis 是一种常用的内存缓存工具&#xff0c;但在某些情况下&#xff0c;它可能会遭受缓存雪崩、缓存穿透和缓存击穿等问题。下面是一些预防这些问题的建议&#xff1a; 1、缓存雪崩 缓存雪崩指的是在某个时间点上&#xff0c;大量的缓存数据同时失效或过期&#xff0c;导致大…

从管易云到金蝶云星空通过接口配置打通数据

从管易云到金蝶云星空通过接口配置打通数据 数据源平台:管易云 管易云是上海管易云计算软件有限公司旗下的专注提供电商企业管理软件服务的品牌&#xff0c;总部位于中国上海张江高科技产业园区。管易云旗下拥有管易云C-ERP、EC-OMS、EC-WMS、B2C/B2B/BBC/微商城开发、PDA无纸化…

【送书】从不了解用户画像,到用画像数据赋能业务看这一本书就够了丨《用户画像:平台构建与业务实践》

系列文章目录 送书第一期 《用户画像&#xff1a;平台构建与业务实践》 文章目录 系列文章目录前言一、内容简介二、目录三、本书摘要简介总结 前言 在大数据时代&#xff0c;如何有效地挖掘数据价值并通过画像数据进行呈现&#xff0c;如何基于画像数据构建平台功能并提高业…

大数据之Hadoop

大数据 按顺序给出数据存储单位&#xff1a; bit 、 Byte 、 KB、 MB 、 GB 、 TB 、 PB 、 EB 、 ZB 、 YB 、 BB 、 NB 、 DB 。 1Byte 8bit 1K 1024Byte 1MB 1024K 1G 1024M 1T 1024G 1P 1024T Hadoop Hadoop是一个能够对大量数据进行分布式处理的软件框架。 分…

mac怎么把两张图片拼在一起

mac怎么把两张图片拼在一起&#xff1f;在如今的生活中&#xff0c;喜欢摄影的朋友们越来越多。拍照已经成为我们的一种习惯&#xff0c;因为当我们遇到美景或迷人的人物时&#xff0c;总是忍不住按下快门&#xff0c;将它们定格。随着时间的推移&#xff0c;我们渐渐发现自己的…

人工智能安全-2-非平衡数据处理(2)

5 算法层面 代价敏感&#xff1a;设置损失函数的权重&#xff0c;使得少数类判别错误的损失大于多数类判别错误的损失&#xff1b; 单类分类器方法&#xff1a;仅对少数类进行训练&#xff0c;例如运用SVM算法&#xff1b; 集成学习方法&#xff1a;即多个分类器&#xff0c;然…

数据结构--选择排序

目录 选择排序的定义 选择排序的过程 选择排序的算法实现 算法的性能分析 时间、空间复杂度 稳定性 实用性 回顾 选择排序的定义 选择排序的过程 找到最小的元素和第一个元素交换位置 得到 接下来第一个位置不用管了&#xff0c;从剩下的元素中扫描找到最小的元素放到…

[Linux入门]---进程的概念

文章目录 1.进程的概念①描述进程-PCB②task_struct-PCB的一种③task_ struct内容分类 2.查看进程3.通过系统调用获取进程表示符4.通过系统调用创建进程---fork初识 1.进程的概念 在我们的电脑开机的时候&#xff0c;操作系统会被加载到内存中&#xff0c;点击多个应用进行时&a…

【微信小程序开发】宠物预约医疗项目实战-注册实现

【微信小程序开发】宠物预约医疗项目实战-注册实现 第二章 宠物预约医疗项目实战-注册实现 文章目录 【微信小程序开发】宠物预约医疗项目实战-注册实现前言一、打开项目文件二、编写wxss代码2.1 什么是wxss2.2 配置主程序全局样式 三. 在sign文件下的wxml文件中编写如下代码并…

全网最细讲解如何实现导出Excel压缩包文件

写在前面的话 接下来我会使用传统的RESTful风格的方式结合MVC的开发模式给大家介绍一下如何去实现标题的效果。 基本思路讲解 先从数据库中查询出一组人员信息记录&#xff0c;保存在List list中。遍历这个列表&#xff0c;对于每一个人员信息&#xff0c;将其填充到一个Excel…

BIOMOD2模型、MaxEnt模型物种分布模拟,生物多样性生境模拟,论文写作

①基于R语言BIOMOD2模型的物种分布模拟实践技术应用 针对我国目前已有自然保护区普遍存在保护目标不明确、保护成效低下和保护空缺依然存在等问题&#xff0c;科学的鉴定生物多样性热点保护区域与保护空缺显得刻不容缓。 BIOMOD2提供运行多达10余种物种分布模拟模型&#xff0c…

工具篇 | Gradle入门与使用指南

介绍 1.1 什么是Gradle&#xff1f; Gradle是一个开源构建自动化工具&#xff0c;专为大型项目设计。它基于DSL&#xff08;领域特定语言&#xff09;编写&#xff0c;该语言是用Groovy编写的&#xff0c;使得构建脚本更加简洁和强大。Gradle不仅可以构建Java应用程序&#x…

基于海康Ehome/ISUP接入到LiveNVR实现海康摄像头、录像机视频统一汇聚,做到物联网无插件直播回放和控制

LiveNVR支持海康NVR摄像头通EHOME接入ISUP接入LiveNVR分发视频流或是转GB28181 1、海康 ISUP 接入配置2、海康设备接入2.1、海康EHOME接入配置示例2.2、海康ISUP接入配置示例 3、通道配置3.1、直播流接入类型 海康ISUP3.2、海康 ISUP 设备ID3.3、启用保存3.4、接入成功 4、相关…

PREEvision Client 10.8.0

PREEvision Client 10.6.0 2692407267qq.com&#xff0c;更多内容请见http://user.qzone.qq.com/2692407267/

WebGL HUD(平视显示器)

目录 HUD&#xff08;平视显示器&#xff09; 如何实现HUD 示例程序&#xff08;HUD.html&#xff09; 示例程序&#xff08;HUD.js&#xff09; 代码详解 在网页文字上方显示三维物体 代码详解 HUD&#xff08;平视显示器&#xff09; 平视显示器&#xff08;head…

服务器迁移:无缝过渡指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…