佛山网站设计电话/网络营销公司怎么注册
今日内容
零、 复习昨日
一、作业
二、进程与线程
三、创建线程
四、线程的API
五、线程状态
六、线程同步
零、 复习昨日
晨考
一、作业
见答案
二、进程与线程[了解]
一个
进程就是一个应用程序,进程包含线程
一个进程至少包含一个线程,大部分都是有多条线程在执行任务(多线程)
进程是系统资源分配的最小单位
线程是进程内部的一个执行任务
进程内多个线程是共享进程资源,
线程是资源调度的最小单位
Java程序是否是多线程的吗?
答: 是! 至少有main线程,垃圾回收线程等等
三、创建线程[重点]
Thread
创建线程的方式有很多
继承Thread
实现Runnable接口
- 使用Callable 和Future来完成
- 使用线程池获得线程
3.1 继承Thread
步骤
- 自定义类
- 继承Thread
- 重写run方法
- 创建子类对象
调用start方法启动线程
[特别强调,开启新线程的方法是start
]
start方法内部执行时会调用run方法执行
public class MyThread extends Thread{// 重写方法,方法内部,就是该线程执行的任务@Overridepublic void run() {for (int i = 1; i < 11; i++) {System.out.println("MyThread --> "+i );}}
}
public static void main(String[] args) {// 创建一个线程MyThread myThread = new MyThread( );// 启动线程myThread.start();// ==============main线程执行====================for (int i = 1; i < 11; i++) {System.out.println("main-Thread" + i );}// 自定义线程和主线程同时执行,并且出现资源争抢情况}
使用匿名内部类的形式开启线程
// ==========匿名内部类的方法开启线程==============new Thread(){@Overridepublic void run() {for (int i = 1; i < 1001; i++) {System.out.println("my-Thread-2 --> " + i );}}}.start();
myThread线程,main线程,my-Threah-2线程3个在争抢资源,如果没有出现效果,把主线程执行的代码放在最下方,因为主线程代码优先级较高,会优先执行…
3.2 实现Runnable接口
步骤
- 自定义类
- 实现Runnable接口
- 重写run方法
- 创建子实现类对象
- 把子实现类对象当构造方法的方法参数来创建Thread对象
- 由thread调用start方法开启线程
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 1; i < 101; i++) {System.out.println("MyRunnable - 1 --> " + i);}}
}
public static void main(String[] args) {// 4 创建实现类对象MyRunnable myRunnable = new MyRunnable( );// 5 把对象当构造方法参数,创建Thread对象Thread thread = new Thread(myRunnable);// 6 开启线程thread.start();}
匿名内部类的形式创建线程
// ============= 匿名内部类完成实现Runnable接口 ============
new Thread(new Runnable(){@Overridepublic void run() {for (int i = 1; i < 101; i++) {System.out.println("MyRunable-2 --> " + i );}}
} ).start();
3.3 区别
继承Thread开启线程和实现Runnable接口开启线程有什么区别?
- 一个继承,一个实现
- 继承Thread后,直接创建对象即可调用start开启线程
- 实现Runnable接口的子类,还需要再创建Thread类对象才可以调用strat开启线程
从使用便捷度来说,继承Thread开启线程会方便一点…
继承Thread类就限制了该类再继承别的类,因为类只能单继承,而实现接口的同时可以继承别的类,并且还允许多继承.
所以推荐使用接口来实现.
四、线程的API[熟悉]
void start() 开启线程
,会自动run方法执行线程任务void run() 执行线程的方法
- run() 方法是start开启线程后,JVM自动调用
- void setName(String name) 给线程设置名字
- 也可以通过构造方法,在创建线程时指定线程名
- String getName() 获得线程的名字
static Thread currentThread()
返回当前正在执行的线程对象- setPriority(int priority) 设置优先级
- 级别是1-10 ,默认是5
- getPriority() 获得优先级
- join() 加入线程,等待该线程终止
- join(int milles) 加入线程,最大等待直到毫秒数
- void setDaemon(boolean on) 设置守护线程
static
void yield() 礼让线程,暂停当前线程,让其他线程执行static void sleep(long milles) 线程休眠
- 会让当前线程暂停执行,
让出系统资源
,让其他线程执行- 时间到,当前会继续和其他争抢资源执行
- void stop() 结束当前线程,线程死亡(已过式)
- 被废弃的原因是因为这个中断线程太直接太暴力…
package com.qf.thread;/*** --- 天道酬勤 ---** @author QiuShiju* @desc 演示线程API*/
public class TestThread3 {public static void main(String[] args) {testStop();}/*** 测试线程停止*/public static void testStop() {Thread thread = new Thread("好人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {if (i == 5000) {Thread.currentThread().stop();}System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};thread.start( );}public static void testSleep2() {Thread thread2 = new Thread("人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread( ).getName( ) + " --->" + i);}}};Thread thread = new Thread("好人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {if (i == 500) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace( );}}System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};thread.start( );thread2.start( );}/*** 演示线程休眠*/public static void testSleep() {System.out.println("倒计时.." );for (int i = 5; i > 0; i--) {System.out.println(i );// 线程休眠1秒钟try {// 让当前主线程睡觉Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace( );}}System.out.println("发射!" );}/*** 演示加入线程*/public static void testJoin() {Thread thread2 = new Thread("人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread( ).getName( ) + " --->" + i);}}};Thread thread = new Thread("好人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {if (i == 500) {try {// 线程1(好人)执行到500,让线程2(人)加入执行,直到该线程结束,当前线程再继续执行//thread2.join();// 线程1(好人)执行到500,让线程2(人)加入执行,让其运行指定毫秒时间// 时间到,线程再争抢资源thread2.join(10);} catch (InterruptedException e) {e.printStackTrace( );}}System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};thread.start( );thread2.start( );}/*** 演示礼让线程*/public static void testYield() {Thread thread = new Thread("好人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {// 获得当前正在执行线程对象if (i == 500) {Thread.yield( );}System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};Thread thread2 = new Thread("人") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread( ).getName( ) + " --->" + i);}}};thread.start( );thread2.start( );}/*** 演示守护线程*/public static void testDaemon() {Thread thread = new Thread("皇上") {@Overridepublic void run() {for (int i = 0; i < 1; i++) {// 获得当前正在执行线程对象System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};Thread thread2 = new Thread("妃子") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread( ).getName( ) + " --->" + i);}}};// 开启前设置某个线程为守护线程thread2.setDaemon(true);// 一旦设置一个线程为守护线程,那么其他的线程就是被守护的thread.start( );thread2.start( );}/*** 演示关于线程优先级的方法*/public static void testPriority() {Thread thread = new Thread("和谐号1") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {// 获得当前正在执行线程对象System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};Thread thread2 = new Thread("复兴号2") {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread( ).getName( ) + " --->" + i);}}};// 默认优先级是5,System.out.println(thread.getName( ) + "--->" + thread.getPriority( ));System.out.println(thread2.getName( ) + "--->" + thread2.getPriority( ));// 设置优先级,最高是10,最低是1,不能越界// 注意不是一定优先级高的先执行,只是大概率上会是thread.setPriority(1);thread2.setPriority(10);thread.start( );thread2.start( );}/*** 演示关于线程名字的方法*/public static void testName() {// 通过构造方法设置线程名Thread thread = new Thread("和谐号") {@Overridepublic void run() {for (int i = 0; i < 10; i++) {// 获得当前正在执行线程对象System.out.println(Thread.currentThread( ).getName( ) + " ---> " + i);}}};Thread thread2 = new Thread( ) {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread( ).getName( ) + " --->" + i);}}};// 获得线程名// 默认线程名,从Thread-0开始//System.out.println(thread.getName( ));// 通过setName设置线程名thread2.setName("绿皮");//System.out.println(thread2.getName( ));thread.start( );thread2.start( );// 获得主线程的名字System.out.println(Thread.currentThread( ).getName( ));}
}
五、线程状态[面试]
线程的几种状态:
- 创建/新建/初始
- new 完线程对象
- 就绪
- 调用start
- 等待/阻塞
- join()或者sleep()
- 运行
- 执行run()方法
- 死亡/销毁/终止
- run方法执行完,或者调用stop()或者interrupt()中断等
清楚状态之间的转换
六、线程安全[重点]
6.1 线程安全
临界资源:共享资源(同⼀个对象),一次只可以有一个线程操作,才可以保证准确性
原子操作:不可拆分的步骤,被视作一个整体。其步骤不能打乱
线程不安全: 1) 完整的步骤可能会被破坏 2) 线程内的数据可能被别的线程修改
6.2 线程安全方式
- 同步方法
- 给方法加锁,即设置同步锁关键词
synchronized
- 锁对象是当前对象,即this
- 同步代码块
- 将需要安全的代码使用同步代码块包裹,设置锁对象.
锁可以是任意对象
- 但是线程之前应该是
同一把锁
才能锁住,保证安全
其实就是给需要"同步",需要"安全",需要"步骤一致,不能打乱"的代码
加锁
.
需求: 要求打印机类的两个方法分别被两个线程同时执行.但是方法执行时不能被破坏,即方法执行时不能被另外一个线程抢走资源,要保证方法执行时步骤完整性.
package com.qf.sync;import java.util.Date;/*** --- 天道酬勤 ---** @author QiuShiju* @desc 打印机*/
public class Printer {// 锁需要是同一对象private Object obj = new Object();// 打印机1号public synchronized void print1() {//synchronized (obj){System.out.print(1+" ");System.out.print(2+" ");System.out.print(3+" ");System.out.print(4+" ");System.out.print("\r\n");//}}// 打印机2号public synchronized void print2() {//synchronized (obj) {System.out.print("一 ");System.out.print("二 ");System.out.print("三 ");System.out.print("四 ");System.out.print("\r\n");//}}
}
public static void main(String[] args) {Printer printer = new Printer( );// 线程1new Thread(){@Overridepublic void run() {while(true){printer.print1();}}}.start();// 线程2new Thread(){@Overridepublic void run() {while(true){printer.print2();}}}.start();}
}
换种方式写
public class TestSync2 {public static void main(String[] args) {// 线程1new Thread( ) {@Overridepublic void run() {for (; ; ) {synchronized (TestSync2.class) {System.out.print(1 + " ");System.out.print(2 + " ");System.out.print(3 + " ");System.out.print(4 + " ");System.out.print("\r\n");}}}}.start( );// 线程2new Thread( ) {@Overridepublic void run() {for (; ; ) {synchronized (TestSync2.class) {System.out.print("一 ");System.out.print("二 ");System.out.print("三 ");System.out.print("四 ");System.out.print("\r\n");}}}}.start( );}
}
6.3 转账案例
需求: 假设银行账户类,属性有卡号,余额,名字 ; 另外有ATM机器,机器内能接收账户,给ATM指定取的钱数.ATM支持多线程操作.
// 账户
public class Account {private String id;private double balance;public Account() {}public Account(String id, double balance) {this.id = id;this.balance = balance;}public String getId() {return id;}public void setId(String id) {this.id = id;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}
}
public class ATM extends Thread {private Account account;private double money;// 取钱是多线程操作@Overridepublic void run() {synchronized (ATM.class){if (account.getBalance() >= money) {// 模拟出钱的时间,目的是让出资源,让另外的线程执行,模拟争抢// 加锁后,sleep"抱着锁睡觉",是说线程休眠不会让出锁,即不会让出资源,其他线程无法执行,// 等着这个线程休眠结束并且执行完毕try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace( );}account.setBalance(account.getBalance() - money);System.out.println(Thread.currentThread().getName() + "取钱成功,取出" +money );System.out.println("余额:" + account.getBalance() );} else {System.out.println("你有多少钱,心里没数?!" );}}}public ATM() {}public ATM(Account account, double money,String name) {super(name);this.account = account;this.money = money;}public Account getAccount() {return account;}public void setAccount(Account account) {this.account = account;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}
}
public class Bank {public static void main(String[] args) {Account account = new Account("888888", 1000);new ATM(account,600,"小红").start();new ATM(account,600,"小黑").start();}
}
变式: 转账案例使用Runable接口来实现
练习
售票: 有一个窗口类售票,总共100张票,窗口不止一个可以多个窗口同时售票. 要保证票不能卖超,不能卖重复的票
6.4 线程安全的方式
不只有synchronized同步方法可以保证线程安全,其实还有很多
ThreadLocal
Volatile
Lock
ReentrantLock
等
相关文章:

JavaSE学习笔记总结day18
今日内容 零、 复习昨日 一、作业 二、进程与线程 三、创建线程 四、线程的API 五、线程状态 六、线程同步 零、 复习昨日 晨考 一、作业 见答案 二、进程与线程[了解] 一个进程就是一个应用程序,进程包含线程 一个进程至少包含一个线程,大部分都是有多条线程在执行任务(多线…...

HybridFusion: LiDAR和视觉交叉源点云融合
一、基本信息 研究方向: 大场景点云配准 HybridFusion: 它可以在户外大型场景中从不同视角记录交叉源密集点云。 团队链接:http://www.adv-ci.com 视频链接: https://www.bilibili.com/video/BV1vM41147yD/?spm_id_from333.337.sear…...

走进JVM
JVM的位置 在操作系统之上,可以想象成一个软件,Java程序都运行在上面 JVM结构图 JVM调优的位置 99%的调优在堆中,极少数在方法区中 很多第三方插件都是在执行引擎那块地方做出修改而来,比如Lombook在程序运行时动态生成get/s…...

C语言-基础了解-15-C函数指针与回调函数
C函数指针与回调函数 一、函数指针 函数指针是指向函数的指针变量。 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。 函数指针可以像一般函数一样,用于调用函数、传递参数。 函数指针变量的声明: type…...

react和vue在响应式上的不同理解
vue和react的区别总是被提及,关于这个问题最近也有了自己的想法。我认为它们之间最大的区别是对于响应数据变化的实现方式不同。 vue实现响应的方法是,首先收集依赖这个数据的副作用(视图更新、计算属性等),当数据修改…...

多线程二 多线程了解与使用
文章目录synchronized 锁有两种synchronized异常捕获主线程和子线程volatile的作用notify是随机启动等待线程中的一个synchronized 锁有两种 类对象类的实例 第一种:锁类对象,有两种方式,如下: // 方法一:synchroni…...

嵌入式 Linux 的僵尸进程是什么?
目录 1、什么是僵尸进程? 2、僵尸进程的目的 3、怎么避免僵尸进程? 4、僵尸进程的处理方法 4.1 wait()连接 4.2 waitpid()函数 1、什么是僵尸进程? 首先内核会释放终止进程(调用了 exit …...

【刷题笔记】笔记一
1.自守数牛客链接解析:1.自守数的结尾肯定是 0,1,5,62.把数字转换为string类(方便比较)3.直接find在s2 里面 使用find查找另一个即可。#include <iostream> #include<string> using namespace …...

浏览器主页被hao123劫持的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…...

华为OD机试题 - 热点网络统计(JavaScript)| 含代码编写思路
华为OD机试题 最近更新的博客使用说明本篇题解:热点网络统计题目输入输出描述示例一输入输出示例二输入输出Code解题思路华为OD其它语言版本最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华…...

IT项目经理的自我修养手册
在不断进步的时代,任何岗位职责都是一个责任、权力与义务的综合体,有多大的权力就应该承担多大的责任,有多大的权力和责任应该尽多大的义务,任何割裂开来的做法都会发生问题。那么作为IT项目经理的岗位职责,我大概列举…...

2023年软考中级电子商务设计师考什么?
首先,电子商务设计师属于软考中级,因此难度也不是特别大。但并不是说就完全没有难度,难度还是有的,像上午题一般把基本知识点掌握了,是没什么问题的,重点就在于下午题会比较难。 接下来我们来剖析一下考试…...

现在的00后太强了,几个问题差点给我问懵了
前言 我们公司刚入职一个00后小伙,今天在办公室交流了一下,他问我会不会自动化测试,我说懂一点,然后直接问了我几个自动化测试问题,差点直接给我问懵了! 问题如下: 我们在制定自动化测试实施…...

$3 : 水项目实战 - 水果库存系统
javase知识点复习: final关键字:http://t.csdn.cn/bvFgu 接口的定义,特性,实现,继承:http://t.csdn.cn/tbXl3 异常:http://t.csdn.cn/VlS0Z DAO的概念和角色(设计理念)&a…...

毕业设计 基于STM32单片机无线ZIGBEE智能大棚土壤湿度光照检测
基于STM32单片机无线ZIGBEE智能大棚土壤湿度光照检测1、项目简介1.1 系统构成1.2 系统功能2、部分电路设计2.1 STM32F103C8T6核心系统电路设计2.2 光敏采集电路设计2.3 温度采集电路设计3、部分代码展示3.1 读取DS18B20温度值3.2 定时器初始化1、项目简介 选题指导,…...

华为OD机试真题Java实现【相对开音节】真题+解题思路+代码(20222023)
相对开音节 题目 相对开音节构成的结构为辅音+元音(aeiou)+辅音(r除外)+e,常见的单词有bike、cake等。 给定一个字符串,以空格为分隔符,反转每个单词中的字母,若单词中包含如数字等其他非字母时不进行反转。 反转后计算其中含有相对开音节结构的子串个数(连续的子串…...

【C++】30h速成C++从入门到精通(STL容器listvector)
listlist的介绍list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。list与…...

操作系统---存储管理
存储管理 操作系统将外存的文件调入到内存中,以便CPU调用,如果调用的内容不在内存中,则会产生缺页中断;产生缺页中断后,这事需要从外存调数据到内存中,然后CPU接着从断点继续调用内存中的数据;在…...

华为OD机试题 - 好朋友(JavaScript)| 含思路
华为OD机试题 最近更新的博客使用说明本篇题解:好朋友题目输入输出示例一输入输出说明示例二输入输出说明Code解题思路华为OD其它语言版本最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典...

socket本地多进程通信基本使用方法和示例
目录 前言: socket是什么 socket基本原理框图 socket基本函数 1 socket() 函数 2 bind()函数 3 connect()函数 4 listen() 函数 5 accept() 函数 6 read() write() send() recv()函数 7 close()函数 8 字节序转换(hton) 示例代码 …...

Python 算法交易实验51 Step2 Signals 信号生成
说明 不可不读书 先从经典的一些超简单信号开始 使用移动平均指标SMA(算术) 给出了信号的产生方法,还有一些测算结果,反正看起来都是盈利的 首先使用离线方法实验一组结果,然后就使用ADBS来进行类似的处理。 内容 1 原理分析…...

app上架专用软著认证电子版权在主流应用商店的使用说明2023年最新版
软著认证电子版权在主流应用商店的使用说明 目录 一、 华为应用商店 二、 腾讯应用宝 三、 小米开放平台 小米应用提交: 小米游戏提交: 四、 OPPO开放平台 OPPO应用提交: OPPO游戏(App)提交: OPPO小游戏(快应…...

[Mybatis2]Mapper代理开发
文章目录 问题情境 代理开发 遵循的三条原则 1.定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下 2.设置SQL映射文件的namespace属性为Mapper接口的全限定名 3.在Mapper接口中定义方法,方法名就是SQL映射文件中sql…...

第十一届蓝桥杯大赛青少组国赛Python真题2
第十一届蓝桥杯大赛青少组Python 真题 第二题 提示信息: 杨辉三角形,是二项式系数在三角形中的一种几何排列。中国南宋数学家杨辉在 1261 年所著的《详 解九章算法》一书有明确记载。欧洲数学家帕斯卡在 1654 年发现这一规律,所以又叫做帕斯卡…...

创建springboot项目文件报红
目录 一、遇到问题 二、出现这个问题的原因 三、解决办法 三种方法 四、操作步骤 一、遇到问题 创建springboot项目的时候,会发现一些重要文件都变成红色了,但是不影响程序的运行。只是看起来会有点不舒服。 二、出现这个问题的原因 因为这个spr…...

gma 地理空间绘图:(1) 绘制简单的世界地图-3.设置地图框
内容回顾 gma 地理空间绘图:(1) 绘制简单的世界地图-1.地图绘制与细节调整 gma 地理空间绘图:(1) 绘制简单的世界地图-2.设置经纬网 方法 SetFrame(FrameColor ‘black’, FrameWidth 0.6, ShowFrame True, ShowLeft True, ShowBottom True, Sho…...

Java Web 实战 03 - 多线程基础(2)
Java Web 实战 03 - 多线程基础篇 2二 . Thread类常见方法2.1 Thread 的常见构造方法2.2 Thread 的几个常见属性getId()getName()getState()getPriority()isDaemon()案例 : 实现 getId()、getName()、 getState()、getPriority()、isDaemon()、isAlive()2.3 启动一个线程-start…...

Linux命令·cat
cat命令的用途是连接文件或标准输入并打印。这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用。 1.命令格式:cat [选项] [文件]...2.命令功…...

WPF WrapPanel、UniformGrid、DockPanel介绍
WPF WrapPanel、UniformGrid、DockPanel介绍 WrapPanel WrapPanel , 具有在有限的容器范围内, 可以自动换行, 或者换列处理。具体则取决于WrapPanel的排列方式 (Orientation)。 Orientation"Horizontal"时各控件从左至右罗列,当面板长度不够时ÿ…...

华为OD机试题 - TLV 编码(JavaScript)| 含思路
华为OD机试题 最近更新的博客使用说明本篇题解:TLV 编码题目输入输出描述示例一输入输出说明Code解题思路华为OD其它语言版本最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流…...