当前位置: 首页 > news >正文

java进阶 1.0.2

来啦,多线程
首先要理解计算机中对多任务的处理
一台计算机为什么能够在执行多个程序?他们是怎么执行多个程序的?
电脑是有很多个进程的
计算机的鼻祖想了一个新方法:如果不能同时使用,那就进行切换
比如现在我要使用火狐浏览器了,现在使用的csdn就被挂起了,相当于是暂停
表面上看是同时运行了两个程序,但是其实是切换的速度非常快
这是只有一个核的情况
但是现在富裕了,我弄了好几个核,就是不用来回切换了
在这里插入图片描述
这就是现在电脑常说的,多少多少核处理器,多少多少线程
这样就可以同时进行事情,核心数越多干活就不累,人多力量大
在这里插入图片描述
这是主包的电脑捏
但是也需要来回切换
打开第一个进程,第二个进程就关闭
所有的程序都会占一个进程,有的软件占一个有的占好几个
一个进程会给多个人用,这个就是线程
核心下面有多个进程
一个进程下边又会有多个线程
现在说的八核心十六线程,这里的线程就是下面说的这个东西,线程数越多,来回切换的速度就越快
进程和线程的区别
先来一组传神的图片
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
并发和并行的区别
在这里插入图片描述
在这里插入图片描述
进程是操作系统分配资源的单位,线程是调度的基本单位,线程之间共享进程资源

在这里插入图片描述
由于线程运行的本质就是函数运行,函数运行时信息是保存在栈帧中的,因此每个线程都有自己独立的、私有的栈区。
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多线程程序含义和作用的提出
一个应用程序可能占据一个进程
对一个应用程序的某个共享变量进行操作
java中的线程该如何去创建
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这是运行结果
main函数是一个线程,现在是又创建了一个线程,这里是两个线程同时运行
但是这里的run方法并不是多线程的,frank你在搞什么?!!
需要使用别的方法start而不是run
为了表示的更明显一点
在这里插入图片描述
在这里插入图片描述
注意这里在main之前一定要先start这个线程

在这里插入图片描述
可以发现,欸?不是两个死循环吗,这就体现出了多线程的特性
两个线程在同时进行,因为两个线程切换的特别快
就是看哪个线程谁先抢到,就执行谁
写自己的线程
重写run方法,然后使用start开启就好了
就相当于两个线程一直在抢,就看谁抢到,谁抢到就是谁
因为main只能是一个线程
多线程的执行过程
不能再从传统的意义上来理解了
以前的main是一条线,就是顺着往下
main本来就是一个线程,叫做主线程
在这里插入图片描述
这样来理解多线程执行
第二重方式是使用接口的方法创建一个线程
但是和thread相比,这种方式有较多的局限性
java是单继承的,意味着你要使用一个线程的话。就只能继承Thread然后不能使用别的功能了,java只能继承一个类
这样的话就得使用第二种接口的方式

public class YYYThread implements Runnable{// 接口也需要重写run@Overridepublic void run() {while (true) {System.out.println("YYYThread is running..........");}}
}

注意这里就换成了接口

public class Demo {public static void main(String[] args) {YYYThread yThread = new YYYThread();Thread yyyTread = new Thread(yThread);yyyTread.start();while (true) {System.out.println("main..........run........");}}
}

这里创建的时候都是有讲究的,先创建一个自己线程的对象
然后创建一个Thread类的对象,只有这样才能使用Thread的start方法,不然没法启动这个线程
在这里插入图片描述
这是运行结果
简化操作以及线程名
在这里插入图片描述
使用匿名内部类的方法就不用起名字了,怪麻烦的
在这里插入图片描述
顺带起个名字还是好的,这就相当于给新开的线程起了一个名字
在这里插入图片描述
可以看到是有这样的构造方法的
修改成这个样子就可以获取刚刚写的名字了

public class YYYThread implements Runnable{// 接口也需要重写run@Overridepublic void run() {while (true) {System.out.println("YYYThread is running.........." + Thread.currentThread().getName());}}
}

很多时候是不需要new一个对象的,直接放长句里面new就可以
在这里插入图片描述
运行结果
每个线程都是有名字的
并发并行这个东西是很有讲究的,需要学很多东西
来一个多线程案例
多线程概念就是:多个线程共同去操作共享变量
抢占资源,就看谁抢的多
假设现在有100双nike鞋,有三个人去抢

public class YYYThread implements Runnable{private int nike = 100;// 接口也需要重写run@Overridepublic void run() {while (true) {System.out.println(Thread.currentThread().getName() + "抢到了" + (nike--) + "双鞋");}}
}

然后再给他创建三个线程

public class Demo {public static void main(String[] args) {YYYThread yThread = new YYYThread();
//        Thread yyyTread = new Thread(yThread);
//        yyyTread.start();new Thread(yThread, "tom").start();new Thread(yThread, "frank").start();new Thread(yThread, "jone").start();}
}

在这里插入图片描述
这是最后的结果,这就是多个线程抢着去操作一个共享变量
如果使用继承Thread的方法不太好
因为implements接口的方法适合这样的场景
企业里边有更好的解决办法
当有人问你多线程的时候,你就告诉他不是并行也不是并发,就是多个人去抢,就看是谁抢的快
后台守护线程的提出
有前台的线程和进程,那这就意味着也有后台的进程和线程
后台的线程有一个好听的名字------守护线程
如果想要把一个普通的线程变成守护线程只需要调用方法就行
但是有一些注意事项
守护线程在使用之前一定要new出来,一个是最开始执行的,优先级比较高,执行后台线程,才执行前台线程

public class Demo {public static void main(String[] args) {YYYThread yThread = new YYYThread();DaemonTread daemonTread = new DaemonTread();Thread dthread = new Thread(daemonTread);dthread.setDaemon(true);dthread.start();
//        Thread yyyTread = new Thread(yThread);
//        yyyTread.start();new Thread(yThread, "tom").start();new Thread(yThread, "frank").start();new Thread(yThread, "jone").start();}
}

setDaemon方法就设置为了后台线程,注意一定要他先开始start
在这里插入图片描述
运行结果,他是第一个运行的
在这里插入图片描述
还可以判断一个线程是否是守护线程
前台线程是用来抢的
但是后台线程是用来更新的,一直在运行
比如可以告诉nike鞋子买完了?
这个等待主包查资料看一下
匿名内部类创建线程

new Thread(new Runnable() {@Overridepublic void run() {System.out.println("匿名内部类");}}).start();

也可以使用这样的方式来创建
发现问题:提出synchronized的概念
来模拟一下真实的抢鞋操作,每个人都会有几秒的下单时间

public void run() {while (true) {// 模拟人类抢鞋的速度try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}if (nike > 0) {System.out.println(Thread.currentThread().getName() + "抢到了" + (nike--) + "双鞋");}}}

上面休眠100ms来模拟实际的下单速度
再次运行在这里插入图片描述
出现了很奇怪的问题,怎么会有两个人同时抢到第4双鞋
这个不处理好是要出大麻烦的
这种问题叫做线程非安全,线程不同步
正确的应该是同步的,如果有人买鞋之后就应该及时的把数据库更新一遍
有一个非常好的解决方案
一个解决方法是一个用户抢到鞋之后就喊停,停停停,你让我更新一下,把这个鞋删除了,然后再开始抢
在修改共享资源的时候一定要注意线程同步,两个人速度一样的话,同时抢到就不好了

public class YYYThread implements Runnable {private int nike = 10;// 创建一个锁对象Object lock = new Object();// 接口也需要重写run@Overridepublic void run() {synchronized (lock) {while (true) {// 模拟人类抢鞋的速度try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}if (nike > 0) {System.out.println(Thread.currentThread().getName() + "抢到了" + (nike--) + "双鞋");}}}}
}

创建一个锁对象
然后使用synchronized关键字把他扩起来
这样就不会出现同时抢一个的现象
我的理解就是规定一次只能一个人买,一个人买完下一个人买
不过一般都是使用方法来做这个

public class YYYThread implements Runnable {private int nike = 10;Lock reentrantLock = new ReentrantLock();// 接口也需要重写run@Overridepublic void run() {while (true) {// 模拟人类抢鞋的速度reentrantLock.lock();try {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}if (nike > 0) {System.out.println(Thread.currentThread().getName() + "抢到了" + (nike--) + "双鞋");}}finally {reentrantLock.unlock();}}}
}

使用Lock创建一个ReentrantLock类,因为Lock是一个接口,不能直接new,而是要new实现这个接口的类
然后在这个程序开始之前reentrantLock.clock();
这样就相当于把这个口子锁上了

ReentrantLock lock = new ReentrantLock();
public void calculate(){lock.lock();try{}finally{lock.unlock();}
}

这里上锁的方法使用甲骨文推荐的写法
这是同步锁的方法,这种手段的操作可能更强一些
为什么和frank的写法现在不能用了
推荐使用ReentrantLock
感觉主包需要加强一些java理论知识的学习了,感觉现在的知识还是好零散
frank说实际区别
看实际中的开发需求
如果需求满足的情况下使用synchronized,需求满足的话使用这个还是不错的

http://www.xdnf.cn/news/574543.html

相关文章:

  • ai建模平台:AnKo革新智能创作体验新纪元!
  • 以加减法计算器为例,了解C++命名作用域与函数调用
  • Vue3使用DataV报错无法使用的解决方案
  • 使用allure生成自动化测试报告
  • 通过TDE透明加密实现SQL Server数据库免改造加密
  • 反弹shell
  • MySQL临时表和内存表
  • C11 日期时间处理案例
  • AtCoder 第406场初级竞赛 A~E题解
  • 学习黑客了解密码学
  • Coze工作流-变量以及变量的类型讲解
  • 最新版Chrome浏览器调用ActiveX控件之eDrawings Viewer专用包v2.0.42版本发布
  • 【AI流程应用】智能知识库搭建与实战应用
  • RK3588 RKNN ResNet50推理测试
  • Spring 定时器和异步线程池 实践指南
  • COMP3023 Design and Analysis of Algorithms
  • ./build/mkfs.jffs2: Command not found
  • 车载诊断架构 --- LIN 节点 ECU 故障设计原则
  • C++继承:从生活实例谈面向对象的精髓
  • 零基础设计模式——创建型模式 - 生成器模式
  • 时源芯微|六大步骤解决EMC问题
  • RAG系统的现实困境与突破:数据泥潭到知识自由
  • QT的自定义控件
  • 【题解-洛谷】B4302 [蓝桥杯青少年组省赛 2024] 出现奇数次的数
  • 数据库——redis
  • 测试--自动化测试概念
  • java21
  • BISS0001:高性能热释电红外感应IC的详细介绍
  • 学习STC51单片机10(芯片为STC89C52RC)
  • 近场探头阵列技术解析