Day 20 03.21 线程 线程同步

Day 20
0321
在这里插入图片描述

hashMap和hashtable的区别

1、两者在api的操作上基本上一样,没有太大的区别
2、hashMap允许空键空值(null键只能出现一次),hashtable不允许出现null键null值
3、hashMap线程不安全,hashTable线程安全
4、Hashmap效率高些,hashtable更低

treeMap

在这里插入图片描述
红黑算法
entry
key value left right black

treemap底层是采用红黑树算法来进行数据的查找,红黑树的每一个节点都是一个entry,里面包含了key value left right color ,root节点默认是黑色的 ,entry是根据k来进行排序的,entry节点包含的内容为value。

entry排序是按照key来排的,key是放在treeset,entry的key要比较大小根据比较器comparator来进行判断的

size:红黑树的节点个数

线程

在这里插入图片描述

线程概述
在这里插入图片描述

理解进程和线程

进程:运行中的应用程序称为进程,进程拥有CPU和内存资源
线程:线程是进程中的一段代码,一个进程 可以有多段代码(一个进程包含多个线程),线程本身不拥有资源的。共享所有进程的资源

多进程:在操作系统中能同时运行多个任务(qq,eclipse)
多线程:在同一个应用程序中,有多个顺序流(多段代码)在同时执行(qq视频,发图片)

代码的理解
在这里插入图片描述
开启这个程序的时候,在操作系统里面产生一个进程,进程是main方法开始的,当执行main方法的时候,在当前进程里面开启一个线程(主线程),main调用method1方法,main进入到methd1继续执行代码,main里面的其他代码无法马上执行,必须等待method1执行完 了再回来执行main的输出语句。

整个程序从开始到结束都只有一个线程,单线程程序,执行路径只有一条。

单线程:一个任务完了继续后面任务,不能同时执行,所花的时间所有任务加在一起。

进程:
1、把应用程序代码放在内存中的代码区,代码放在方法区并没有马上执行,但是这个时候说明一个进程正在准备开始,进程产生,但是没运行,进程其实是一个静态的概念。
2、进程的执行指的是进程里面的主线程开始执行的。main方法的执行,在机器上运行任务的全都是线程。

windows操作系统时多进程的系统,同时可以执行很多的线程,Linux、Unix
Dos是单线程系统

思考?多线程表示多个任务同时执行,CPU如何来分配资源*

Cpu运行速度是非常快,一秒钟几亿次,所以将CPU的运行时间分为一个一个的小片段,每个任务都可以在一个时间片段里面执行一次,如果在当前片段里面没有执行完,其他任务执行完了继续执行。因为速度很快,给我们的感觉同时在执行。
实际上 在一个时间节点上只有一个任务在执行

如果你的电脑是双CPU、多核、实现真正多线程

java是如何去创建线程

4种:
1、继承java.lang.Thread类,当前类就表示多线程类
2、实现Runnable接口,也可以表示多线程类
3、实现Callable接口,也可以实现多线程
4、线程池

Thread.currentThread()可以获取到当前执行的线程。通过它获取线程的信息(名字、id、其他)

线程体,多线程任务都在run里面执行

public void run(){

}

==========================================

第一种:
继承Therad类
1.产生一个线程对象
2.启动线程
(创建一个构造方法,实现区分多个线程的运行)
线程体

在这里插入图片描述在这里插入图片描述

=====================================

第二种
实现Runnable
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
重新new一个Thread类,将当前线程放进去

==============================================

(创建一个构造方法,实现区分多个线程的运行)
在这里插入图片描述
多线程任务进行
在这里插入图片描述
获取当前线程的名字
Thread。currentThread()。getName()
在这里插入图片描述

启动线程start,为什么调用它而不是调用run?

api提出start才是启动线程方法,run线程体,直接调用相当于直接调用方法。产生多线程程序start,将线程放入到线程组(线程队列 先进先出),接下来在调用本地方法start0(),通知虚拟机来执行线程,虚拟机默认会调用线程的run方法来执行。所以一定执行start方法。

线程优先级的问题

java提供了一个线程调度器来监控程序中启动后进入就绪状态的线程。线程调度器会根据线程优先级来判断先调度哪个线程执行。

线程优先级用数字1-10表示,值越大优先级越高,默认缺省值为5(主线程默认都是5)
程序的运行结果还是由虚拟机来安排,无法预知运行后的结果,线程优先级高低只是一个参考值,相对的结果,理论上是具有高优先级的程序占有更多的CPU使用权,但是有时候并不是这样的结果。

================================
prioity:优先级
打印当前线程优先级
在这里插入图片描述

setPrioity();设置优先级
getPrioity();获取优先级

线程的生命周期

五种状态
1、新建
2、就绪
3、运行
4、阻塞
1、等待阻塞
2、同步阻塞
3、其他阻塞
5、死亡

其他阻塞:
sleep()、join()、I/O操作
线程主动让出执行权:yield

sleep:Thread.sleep() sleep属于Thread静态方法,单位是毫秒,一旦调用sleep,当前线程处于睡眠状态,当睡眠时间过去后马上恢复就绪状态,此方法会造成线程阻塞
代表当前线程休眠

join:合并某个线程,如果有两个线程A\B,A必须等待B运行完了才能继续往下运行,我们可以调用join来完成这项工作。合并过后就相当于以前直接调用方法()

yield:在多线程运行过程中,当前抢到CPU资源的线程想让出使用权,调用yield方法马上就让出使用权变成就绪状态,但是还可能被jvm分配使用权。在实际开发中,无法保证yield让步。

线程的同步
什么是同步

多个线程同时运行,有时候线程之间要共享数据,一个线程需要其他线程的数据,否则就不能保证程序的运行结构。

并发 同一个时间点,多个线程访问统一资源
==共享资源(临界资源)*==多个线程共享数据成为共享资源,或者成为临界资源。

==线程同步:==同步就是协同步调的意思,按照预先先后顺序进行执行,先抢到资源的线程先执行,后抢到资源的线程后执行,两个线程相互配合,共享数据。
==线程互斥==对个线程在共享某一个变量,而且都对变量有修改,如果不考虑在运行过程中 用户协调问题,就会出现数据不一致,数据安全问题。

在java中要实现多线程同步:
1、同步块
2、同步方法
3、volatile关键字

同步块:相当于自动加上内置锁,实现同步操作
语法:

synchronized(){
//代码只能在同一时间一个线程访问
}

同步方法:
在方法访问修饰符后加上synchronized

public synchronized void add(){
}

在java中每个对象都会有一个内置锁,当你使用synchronized关键字的时候,内置锁会保护整个方法,在调用方法前需要获取到内置锁,否则处于等待状态。

volatile关键字:
给局部变量的访问提供了一种免锁机制,一个变量使用它来修饰告诉虚拟机该域可能会被其他线程更新,每次使用当前值得时候,都要重新计算一下。默认的值保存寄存器,所以线程互斥就是直接取寄存器的数据,volatile不会提供任何原子操作,也不能用final来修饰。

=================================================

其他阻塞介绍及使用:

Thread.sleep
代表当前线程休眠

在这里插入图片描述

========================================

结束子线程方法1:(一般使用方法一)
子线程循环
while(boo=true)
在这里插入图片描述
主线程睡眠后结束子线程

在这里插入图片描述

方法二:

主线程调用interrupt表示将当前运行的线程打断
线程被打断之后会抛出异常
在这里插入图片描述
子线程抛异常之后要写return
在这里插入图片描述

================================================
join 合并线程
将子线程合并到主线程中
子线程先执行完了 再执行主线程
线程名。join();
在这里插入图片描述

==================================================
IO阻塞
io阻塞让出cpu,让主线程运行
子线程输入输出,主线程运行完毕后子线程才开始运行

==================================================
yield
让出资源(资源让出来的话,并不是说别的线程一定会使用当前资源)

主线程:
在这里插入图片描述

子线程
Thread。yield;
在这里插入图片描述

===========================================

线程同步

同步块使用

未使用同步块
在这里插入图片描述
使用同步块:
synchronized(this){
}
this表示当前对象
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

========================
同步方法的使用
在这里插入图片描述

volatile关键字使用
在这里插入图片描述
可能会遇到的情况:
在这里插入图片描述
使用static修饰
在这里插入图片描述

============================================

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,根据您的要求,以下是Python代码实现: ``` import csv constellation_list = [ ('Aries', '03.21-04.19'), ('Taurus', '04.20-05.20'), ('Gemini', '05.21-06.21'), ('Cancer', '06.22-07.22'), ('Leo', '07.23-08.22'), ('Virgo', '08.23-09.22'), ('Libra', '09.23-10.23'), ('Scorpio', '10.24-11.22'), ('Sagittarius', '11.23-12.21'), ('Capricorn', '12.22-01.19'), ('Aquarius', '01.20-02.18'), ('Pisces', '02.19-03.20') ] def get_constellation(month, day): day_in_month = [ 0, # 0 位未使用 20, # 1 - 1 月 50, # 2 - 2 月 79, # 3 - 3 月 110, # 4 - 4 月 141, # 5 - 5 月 172, # 6 - 6 月 203, # 7 - 7 月 234, # 8 - 8 月 265, # 9 - 9 月 295, # 10 - 10 月 325, # 11 - 11 月 355, # 12 - 12 月 ] if month < 1 or month > 12 or day < 1 or day > 31: return "输入日期错误!" if day < day_in_month[month]: return constellation_list[month-1][0] else: return constellation_list[month][0] def get_constellation_by_date(date): try: year = int(date[0:4]) month = int(date[4:6]) day = int(date[6:8]) except: return "输入日期错误!" return get_constellation(month, day) with open('const.csv', 'r', encoding="UTF-8") as csvfile: reader = csv.reader(csvfile) for row in reader: name = row[0] month = int(row[1]) day = int(row[2]) correct_name = get_constellation(month, day) if correct_name != name: print('有错:{} 的生日是{}月{}日,应该是{}座,而不是{}座'.format(name, month, day, correct_name, name)) print(get_constellation_by_date('19930918')) print(get_constellation_by_date('20200231')) ``` 上面的代码,我们在代码最开始定义了星座列表`constellation_list`,里面存放了每个星座的名字及其起止日期。 接着,我们定义了一个`get_constellation()`函数,用于根据月份和日期计算对应的星座名称。该函数的实现过程为:首先,创建了一个存放每月最后一天的列表`day_in_month`,其0位未使用,1~12位为相应月份的最后一天;然后,如果输入的月份或日期不合法,就返回一个“输入日期错误!”的提示;否则,当输入的日期小于相应月份的最后一天时,返回相应的星座名称,否则返回下一个月份的星座名称。 接着,我们定义了一个`get_constellation_by_date()`函数,用于读取`const.csv`文件并根据用户输入的出生日期获取对应的星座名称。该函数首先尝试将输入日期的年、月、日解析成整数,如果出错则返回一个“输入日期错误!”的提示;否则,调用`get_constellation()`函数计算对应的星座名称并返回。 最后,我们读取了`const.csv`文件并分别调用了`get_constellation_by_date()`函数获取了两个日期的星座名称,分别为白羊座和“输入日期错误!”(因为2月份只有28/29天,而这里输入的是30号,所以日期不合法)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值