当前位置: 首页 > 编程日记 > 正文

多线程threading

threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。

1.     threading模块提供的类:

Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

2.     threading 模块提供的常用方法:

threading.currentThread(): 返回当前的线程变量。

threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

3.     threading 模块提供的常量:

threading.TIMEOUT_MAX 设置threading全局超时时间。

4.     Thread类

isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。

get/setName(name): 获取/设置线程名。

start():  线程准备就绪,等待CPU调度

is/setDaemon(bool): 获取/设置是后台线程(默认前台线程(False))。(在start之前设置)

如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止

如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

start(): 启动线程。

join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。

#coding=utf-8
import threading
def thread_job():print('This is a thread of %s' % threading.current_thread())def main():thread = threading.Thread(target=thread_job,)   # 定义线程 thread.start()  # 让线程开始工作if __name__ == '__main__':main()
threading.Thread()
#coding=utf-8
import threading
def thread_job():print('This is a thread of %s' % threading.current_thread())
def main():thread = threading.Thread(target=thread_job,)   # 定义线程 
    thread.setDaemon(False)thread.start()  # 让线程开始工作
if __name__ == '__main__':print("1")main()print("2")
'''output:
1
2
This is a thread of <Thread(Thread-1, started 9424)>
'''#coding=utf-8
import threading
def thread_job():print('This is a thread of %s' % threading.current_thread())
def main():thread = threading.Thread(target=thread_job,)   # 定义线程 
    thread.setDaemon(True)thread.start()  # 让线程开始工作
if __name__ == '__main__':print("1")main()print("2")
'''output:
1
2
'''
setDaemon
#coding=utf-8
import threading
def thread_job():print('This is a thread of %s' % threading.current_thread())def main():thread = threading.Thread(target=thread_job,)   # 定义线程 
    thread.setDaemon(True)thread.start()  # 让线程开始工作
    thread.join()
if __name__ == '__main__':print("1")main()print("2")'''output:
1
This is a thread of <Thread(Thread-1, started daemon 5292)>
2
'''#coding=utf-8
import threading
def thread_job():print('This is a thread of %s' % threading.current_thread())def main():thread = threading.Thread(target=thread_job,)   # 定义线程 #thread.setDaemon(True)thread.start()  # 让线程开始工作
    thread.join()
if __name__ == '__main__':print("1")main()print("2")
'''output:
1
This is a thread of <Thread(Thread-1, started 9220)>
2
'''#coding=utf-8
import threading
def thread_job():print('This is a thread of %s' % threading.current_thread())def main():thread = threading.Thread(target=thread_job,)   # 定义线程 #thread.setDaemon(True)thread.start()  # 让线程开始工作#thread.join()
if __name__ == '__main__':print("1")main()print("2")
'''output:
1
2
This is a thread of <Thread(Thread-1, started 10032)>
'''
join

1、setDaemon默认是False,无论主程序是否执行完,子程序必须都要执行完,只有等主、子程序都执行完才会退出程序(先后关系不一定是按代码至上向下执行---非阻塞式。)

import threading,time
def job1():global Afor i in range(2):A+=1time.sleep(1)print('job1',A)
def job2():global Afor i in range(2):A+=10time.sleep(2)print('job2',A)
if __name__== '__main__':print("begin")lock=threading.Lock()A=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.start()t2.start()print("end")'''output:
begin
end
('job1', 11)
('job2', 12)
('job1', 22)
('job2', 22)
'''
setDaemon

2、setDaemon默认是True,无论子程序是否执行完,主程序只要执行完就会退出程序。(先后关系不一定是按代码至上向下执行---非阻塞式。)

import threading,time
def job1():global Afor i in range(2):A+=1time.sleep(1)print('job1',A)
def job2():global Afor i in range(2):A+=10time.sleep(2)print('job2',A)
if __name__== '__main__':print("begin")lock=threading.Lock()A=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.setDaemon(True)t2.setDaemon(True)t1.start()t2.start()print("end")'''output:
begin
end
'''
setDaemon

3、join方法存按代码至上而下先后执行(必须得执行完中间代码的子线程,才会去执行末行主线程代码)---阻塞式

同一线程对象的start和join是否紧挨着区别:

import threading,time
def job1():print("start the  1st threading")time.sleep(0.5)print("1st threading ends")
def job2():print("start the  2nd threading")time.sleep(2)print("2nd threading ends")
def job3():print("start the  3rd threading")time.sleep(1)print("3rd threading ends")
if __name__== '__main__':print("begins")lock=threading.Lock()first = threading.Thread(target=job1)second = threading.Thread(target=job2)third = threading.Thread(target=job3)first.start()first.join()second.start()second.join()third.start()third.join()print("ends")
'''输出:
begins
start the  1st threading
1st threading ends
start the  2nd threading
2nd threading ends
start the  3rd threading
3rd threading ends
ends
'''
同个线程对象的start和join紧挨着
import threading,time
def job1():print("start the  1st threading")time.sleep(0.5)print("1st threading ends")
def job2():print("start the  2nd threading")time.sleep(2)print("2nd threading ends")
def job3():print("start the  3rd threading")time.sleep(1)print("3rd threading ends")
if __name__== '__main__':print("begins")lock=threading.Lock()first = threading.Thread(target=job1)second = threading.Thread(target=job2)third = threading.Thread(target=job3)first.start()second.start()third.start()first.join()second.join()third.join()print("ends")'''输出:
begins
start the  1st threading
start the  2nd threading
start the  3rd threading
1st threading ends
3rd threading ends
2nd threading ends
ends
'''
同一个线程对象的start和join不紧挨着

小结:个人感觉同一线程对象的start和join最好不要紧挨着。

5、Queue

在多线程函数中定义一个Queue,用来保存返回值,代替return,定义一个多线程列表,初始化一个多维数据列表。

import threading
import timefrom queue import Queuedef job(l,q):for i in range (len(l)):l[i] = l[i]**2q.put(l)def multithreading():q =Queue()threads = []data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]for i in range(4):t = threading.Thread(target=job,args=(data[i],q))t.start()threads.append(t)for thread in threads:thread.join()results = []for _ in range(4):results.append(q.get())print(results)if __name__=='__main__':multithreading()
Queue

6、线程锁

lock在不同线程使用同一共享内存时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程执行运算修改共享内存之前,执行lock.acquire()将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,执行运算完毕后,使用lock.release()将锁打开, 保证其他的线程可以使用该共享内存。

当多个线程同时执行lock.acquire()时,只有一个线程能成功地获取锁,然后继续执行代码,其他线程就继续等待直到获得锁为止。
获得锁的线程用完后一定要释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程。所以我们用try...finally来确保锁一定会被释放。
锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处当然也很多,首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既不能执行,也无法结束,只能靠操作系统强制终止。

import threading,time
def job1():global Afor i in range(2):print("get A_value of job1",A)A+=1print("A + 1 = %d"%(A))time.sleep(1)print("get A_value of job1",A)
def job2():global Afor i in range(2):print("get A_value of job2",A)A+=10print("A + 10 = %d"%(A))time.sleep(3)print("get A_value of job2",A)
if __name__== '__main__':print("begin")lock=threading.Lock()A=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.start()t2.start()t1.join()t2.join()print("end")
'''输出:
begin
('get A_value of job1', 0)
A + 1 = 1
('get A_value of job2', 1)
A + 10 = 11
('get A_value of job1', 11)
A + 1 = 12
('get A_value of job1', 12)
('get A_value of job2', 12)
A + 10 = 22
('get A_value of job2', 22)
end
'''
无线程锁
import threading,time
def job1():global A,locklock.acquire()for i in range(2):print("get A_value of job1",A)A+=1print("A + 1 = %d"%(A))time.sleep(1)print("get A_value of job1",A)lock.release()
def job2():global A,locklock.acquire()for i in range(2):print("get A_value of job2",A)A+=10print("A + 10 = %d"%(A))time.sleep(3)print("get A_value of job2",A)lock.release()
if __name__== '__main__':print("begin")lock=threading.Lock()A=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.start()t2.start()t1.join()t2.join()print("end")
'''输出:
begin
('get A_value of job1', 0)
A + 1 = 1
('get A_value of job1', 1)
A + 1 = 2
('get A_value of job1', 2)
('get A_value of job2', 2)
A + 10 = 12
('get A_value of job2', 12)
A + 10 = 22
('get A_value of job2', 22)
end
'''
有线程锁

7、死锁

死锁现象例子:共享资源A,B;锁lock1,lock2;两个线程threading1,threading2。

个人感觉就是锁中锁:

一个线程threading1里一个锁lock1还没释放A资源(也就是lock1已锁定了A),就想获取另一个锁lock2来得到B资源(也就是想锁定B),所以在等待B资源释放;

一个线程threading2里一个锁lock1还没释放B资源(也就是lock1已锁定了B)就想获取另一个锁lock2来得到A资源(也就是想锁定A),所以在等待A资源释放;

这样因两个线程相互等待资源释放就造成死锁。

#coding=utf-8
import threading,time
def job1():global A,B,lock1,lock2lock1.acquire()for i in range(2):print("获取job1中: A = %d"%(A))A+=1print("A + 1 = %d"%(A))time.sleep(1)print("获取job1中: A = %d"%(A))lock2.acquire()for i in range(2):print("获取job1中: B = %d"%(B))B+=10print("B + 10 = %d"%(B))time.sleep(3)print("获取job1中: B = %d"%(B))lock2.release()lock1.release()
def job2():global A,B,lock1,lock2lock2.acquire()for i in range(2):print("获取job2中: B = %d"%(B))B+=1print("B + 10 = %d"%(B))time.sleep(3)print("获取job2中: B = %d"%(B))lock1.acquire()for i in range(2):print("获取job1中: A = %d"%(A))A+=10print("A + 1 = %d"%(A))time.sleep(1)print("获取job1中: A = %d"%(A))lock1.release()lock2.release()
if __name__== '__main__':print("begin")lock1=threading.Lock()lock2=threading.Lock()A=B=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.start()t2.start()t1.join()t2.join()print("end")
死锁

小结:无论A是否等于B,lock1是否等于lock2,感觉只要存在锁中锁(每个线程里已acquire了还未释放又进行acquire)就会产生死锁。

8、递归锁:

RLock本身有一个计数器,如果碰到acquire,那么计数器+1;如果计数器大于0,那么其他线程无法查收,如果碰到release,计数器-1;直到如果计数器等于0,才会去执行下一个线程。
#coding=utf-8
import threading,time
def job1():global A,B,lock1,lock2lock1.acquire()for i in range(2):print("获取job1中: A = %d"%(A))A+=1print("A + 1 = %d"%(A))time.sleep(1)print("获取job1中: A = %d"%(A))lock2.acquire()for i in range(2):print("获取job1中: B = %d"%(B))B+=10print("B + 10 = %d"%(B))time.sleep(3)print("获取job1中: B = %d"%(B))lock2.release()lock1.release()
def job2():global A,B,lock1,lock2lock2.acquire()for i in range(2):print("获取job2中: B = %d"%(B))B+=1print("B + 10 = %d"%(B))time.sleep(3)print("获取job2中: B = %d"%(B))lock1.acquire()for i in range(2):print("获取job1中: A = %d"%(A))A+=10print("A + 1 = %d"%(A))time.sleep(1)print("获取job1中: A = %d"%(A))lock1.release()lock2.release()
if __name__== '__main__':print("begin")lock1=lock2=threading.RLock()A=B=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.start()t2.start()t1.join()t2.join()print("end")
'''输出:
begin
获取job1中: A = 0
A + 1 = 1
获取job1中: A = 1
A + 1 = 2
获取job1中: A = 2
获取job1中: B = 0
B + 10 = 10
获取job1中: B = 10
B + 10 = 20
获取job1中: B = 20
获取job2中: B = 20
B + 10 = 21
获取job2中: B = 21
B + 10 = 22
获取job2中: B = 22
获取job1中: A = 2
A + 1 = 12
获取job1中: A = 12
A + 1 = 22
获取job1中: A = 22
end
'''
threading.Rlock()

每一个线程job里必须只有一个Rlock对象,有不同的Rlock对象也会产生死锁。如下:

#coding=utf-8
import threading,time
def job1():global A,B,lock1,lock2lock1.acquire()for i in range(2):print("获取job1中: A = %d"%(A))A+=1print("A + 1 = %d"%(A))time.sleep(1)print("获取job1中: A = %d"%(A))lock2.acquire()for i in range(2):print("获取job1中: B = %d"%(B))B+=10print("B + 10 = %d"%(B))time.sleep(3)print("获取job1中: B = %d"%(B))lock2.release()lock1.release()
def job2():global A,B,lock1,lock2lock2.acquire()for i in range(2):print("获取job2中: B = %d"%(B))B+=1print("B + 10 = %d"%(B))time.sleep(3)print("获取job2中: B = %d"%(B))lock1.acquire()for i in range(2):print("获取job1中: A = %d"%(A))A+=10print("A + 1 = %d"%(A))time.sleep(1)print("获取job1中: A = %d"%(A))lock1.release()lock2.release()
if __name__== '__main__':print("begin")lock1=threading.RLock()lock2=threading.RLock()A=B=0t1=threading.Thread(target=job1)t2=threading.Thread(target=job2)t1.start()t2.start()t1.join()t2.join()print("end")
View Code

9、GIL

GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL。
在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

转载于:https://www.cnblogs.com/windyrainy/p/10751091.html

相关文章:

一个简单的程序来使用WiredTiger 存储引擎

前言 WiredTiger 自 mongodb3.0 集成进来之后为mongodb拉回了大量的口碑&#xff0c;从而在mongodb-3.2 版本直接代替了in-memory存储引擎&#xff0c;作为了mongodb的默认存储引擎。其 通过支持Append-only btree lsm-tree 以及 针对磁盘/内存数据结构上的多核和无锁优化&am…

Java项目:网上商城系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述功能 javaweb 网上商城系统&#xff0c;前台&#xff0b;后台管理&#xff0c;用户注册&#xff0c;登录&#xff0c;上哦展示&#xff0c;分组展示&#xff0c;搜索&#xff0c;收货地址管理&…

Linux 启动详解之init

1.init初探 init是Linux系统操作中不可缺少的程序之一。init进程&#xff0c;它是一个由内核启动的用户级进程&#xff0c;然后由它来启动后面的任务&#xff0c;包括多用户环境&#xff0c;网络等。 内核会在过去曾使用过init的几个地方查找它&#xff0c;它的正确位置&#x…

mysql 相关命令

mysqladmin versionmysqladmin statusmysqlshow -u帐号 -p密码 mysqlshow -u帐号 -p密码 库名mysql -u帐号 -p密码 -e SELECT Host,Db,User From db mysqlmysqldump --quick mysql | gzip > /root/mysql.gzmysqladmin create dbtestgunzip < /root/mysql.gz | mysql…

maven 添加数据库驱动

1.电脑上需要安装 apache maven2.下载oracle的jar包 例如我下载的是ojdbc7-12.jar3.cmd执行命令 mvn install:install-file -DgroupIdcom.oracle -DartifactIdojdbc7 -Dversion12 -Dpackagingjar -Dfiled:\jar\ojdbc7-12.jar-Dfile jar包所存放的位置4.pom文件添加&#xff1…

Rocksdb 的 BlobDB key-value 分离存储插件

前言 还是回到传统的 LSM-tree 中&#xff0c;我们key-value 写入时以append形态存放到一个data-block中&#xff0c;多个data-blockmetablock 之类的数据组织成一个sst。当我们读数据以及compaction的时候读到key 之后则很方便得读取到对应的value&#xff0c;一次I/O能够将k…

Java项目:(前端vue后台java微服务)在线考试系统(java+vue+springboot+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 考试流程&#xff1a; 用户前台注册成为学生 管理员后台添加老师&#xff0c;系统将该用户角色上升为老师 老师登录&#xff0c;添加考试,添加题目&#xff0c;发布考试 考生登录前台参加考试&#xff0c…

C++实现stack【栈】

要求&#xff1a; //****file: stack.h/*对stack进行初始化检查stack为空&#xff0c;或已满将整数压入到stack中从stack里弹出整数 不移除任何袁术&#xff0c;讲过stack的内容输出到标准输出Stack类的私有成员如下&#xff1a;一个用于打印错误信息的私有哦成员函数三个私有数…

c#操作Excel整理总结

大家好&#xff0c;这是我在工作中总结的关于C#操作Excel的帮助类&#xff0c;欢迎大家批评指正&#xff01; using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.IO; using Aspose.Cells;namespace MusicgrabTool {p…

C++ std::function<void(int)> 和 std::function<void()> 作为函数参数的注意事项

前言 std::function 作为标准库提供的函数指针&#xff0c;使用起来还是比较方便的&#xff0c;不过在使用过程中有一些需要注意的细节&#xff0c;这里做一个简单的记录。 基本使用 头文件: #include <functional>语法&#xff1a;std::function<return_type(args…

Java项目:网上电商系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;本系统分用户前台和管理员后台。 前台展示后台管理&#xff0c;前台界面可实现用户登录&#xff0c;用户注 册&#xff0c;商品展示&#xff0c;商品明细展示&#xff0c;用户…

C# SQLiteHelper

1 public class SQLiteHelpers2 {3 /// <summary> 4 /// ConnectionString样例&#xff1a;DatasourceTest.db3;Poolingtrue;FailIfMissingfalse 5 /// </summary> 6 public static string ConnectionStri…

[Git] 拉开发分支的代码报错

Git拉开发分支的代码报错&#xff1a; fatal: The remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed 解决办法&#xff1a; git config --global core.compression -1 转载于:https://www.cnblogs.com/MasterMonkInTemple/p/10754596.html

C++ 通过模版工厂实现 简单反射机制

前言 我们知道Java/Python这种语言能够很好得 支持反射。反射机制 就是一种用户输入的字符串到对应实现方法的映射&#xff0c;比如http接口中 用户传入了url&#xff0c;我们需要调用该url对应的方法/函数对象 从而做出对应的操作。 而C 并没有友好得支持这样的操作&#xf…

计算机世界的“十六进制”为什么如此重要

在计算机世界中,十六进制扮演着不可或缺的角色。它以其紧凑的表示形式、与二进制的天然对应关系以及在各个领域的广泛应用,成为了计算机科学中的一把重要工具。总体而言,计算机需要十六进制并非偶然,它是一种为了更好地满足人类理解和处理数据的需求而产生的工具,为计算机科学的发展和应用提供了便利和支持。

面试官:如何实现10亿数据判重?

以 Java 中的 int 为例,来对比观察 BitMap 的优势,在 Java 中,int 类型通常需要 32 位(4 字节*8),而 BitMap 使用 1 位就可以来标识此元素是否存在,所以可以认为 BitMap 占用的空间大小,只有 int 类型的 1/32,所以有大数据量判重时,使用 BitMap 也可以实现。所以数据库去重显然是不行的。而使用集合也是不合适的,因为数据量太大,使用集合会导致内存不够用或内存溢出和 Full GC 频繁等问题,所以此时我们的解决方案通常是采用布隆过滤器来实现判重。

Java项目:校园二手市场系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述&#xff08; IW文档&#xff09; 功能&#xff1a;本系统分用户前台和管理员后台。 本系统用例模型有三种&#xff0c;分别是游客、注册用户和系统管 理员。下面分别对这三个角色的功能进行描…

php中$_REQUEST、$_POST、$_GET的区别和联系小结

php中$_REQUEST、$_POST、$_GET的区别和联系小结 作者&#xff1a; 字体&#xff1a;[增加 减小] 类型&#xff1a;转载php中有$_request与$_post、$_get用于接受表单数据&#xff0c;当时他们有何种区别&#xff0c;什么时候用那种最好。1. $_REQUEST php中$_REQUEST可以获取以…

uva 315 (poj 1144 求割点)

题意&#xff1a;给你一张无向图&#xff0c;求割点的个数。 思路&#xff1a;输入稍微处理一下接着直接套模版。 1 #include <iostream>2 #include <cstdio>3 #include <cstring>4 #include <cstdlib>5 #include <cmath>6 #include <algorit…

SQL学习之计算字段的用法与解析

一、计算字段 1、存储在数据库表中的数据一般不是应用程序所需要的格式。大多数情况下,数据表中的数据都需要进行二次处理。下面举几个例子。 (1)、我们需要一个字段同时显示公司名和公司地址&#xff0c;但这两个信息存储在不同表的列中。 (2)、省份、城市、邮政编码存储在不同…

手把手教你 用C++实现一个 可持久化 的http_server

前言 本文介绍一个有趣的 通过C实现的 持久化的http_server demo&#xff0c;这样我们通过http通信之后的数据可以持久化存储&#xff0c;即使server挂了&#xff0c;数据也不会丢失。我们的http_sever 也就能够真正得作为一个后端server了。 本身持久化这个能力是数据库提供…

【SVN多用户开发】代码冲突解决办法

SVN是一款集中式的代码存储工具&#xff0c;可以帮助多个用户协同开发同一应用程序。 但是SVN不能完全代替人工操作&#xff0c;有时也需要程序员自己进行沟通确认有效的代码。 下面就简单的看一下&#xff0c;常见的代码冲突以及解决方法。 总结起来&#xff0c;无非是&#x…

Java项目:在线宠物商店系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;本系统分用户前台和管理员后台。 系统包括用户的注册登录&#xff0c;狗狗的展示购物车添加以及下 单支付购买&#xff0c;后台有管理员用户&#xff0c;可以操作狗狗的品种&…

字符串中的数字排序

2019独角兽企业重金招聘Python工程师标准>>> public static String getBusiScope(String busiScope){ String regex "\\d{1,2}"; String busiStr""; Pattern pattern Pattern.compile(regex); Matcher matcher pattern.matcher(busiScope…

oo第二单元总结

第二单元总结 第一次作业 一、设计策略 本次作业采用FAFS算法&#xff0c;可直接用输入线程与电梯线程交互&#xff0c;调度器暂时不需要参与&#xff0c;故一共设计三个类三线程&#xff1a;Main类、elevator类及input类&#xff0c;main线程、elevator线程及input线程。main线…

Rocksdb iterator 的 Forward-scan 和 Reverse-scan 的性能差异

前言 最近在读 MyRocks 存储引擎2020年的论文&#xff0c;因为这个存储引擎是在Rocksdb之上进行封装的&#xff0c;并且作为Facebook 内部MySQL的底层引擎&#xff0c;用来解决Innodb的空间利用率低下 和 压缩效率低下的问题。而且MyRocks 在接入他们UDB 之后成功达成了他们的…

Java知多少(29)覆盖和重载

在类继承中&#xff0c;子类可以修改从父类继承来的方法&#xff0c;也就是说子类能创建一个与父类方法有不同功能的方法&#xff0c;但具有相同的名称、返回值类型、参数列表。如果在新类中定义一个方法&#xff0c;其名称、返回值类型和参数列表正好与父类中的相同&#xff0…

Java项目:清新论坛系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;本系统分用户前台和管理员后台。 用户前台主要功能有&#xff1a; 用户注册 用户登录 浏览帖子 回复帖子 修改个人资料 管理员后台的功能有&#xff1a; 管理论坛版块 用户管…

JUnit4.11 理论机制 @Theory 完整解读

最近在研究JUnit4&#xff0c;大部分基础技术都是通过百度和JUnit的官方wiki学习的&#xff0c;目前最新的发布版本是4.11&#xff0c;结合代码实践&#xff0c;发现官方wiki的内容或多或少没有更新&#xff0c;Theory理论机制章节情况尤为严重&#xff0c;不知道这章wiki对应的…

树链剖分——线段树区间合并bzoj染色

线段树区间合并就挺麻烦了&#xff0c;再套个树链就更加鬼畜&#xff0c;不过除了代码量大就没什么其他的了。。 一些细节&#xff1a;线段树每个结点用结构体保存&#xff0c;pushup等合并函数改成返回一个结构体&#xff0c;这样好写一些 struct Seg{int lc,rc,tot;Seg(){lcr…