2021-05-25

day22

学习目标
1:线程的概念
2:Thread类和Runnable接口
3: 主线程与线程的生命周期
4:线程状态控制方法(sleep休眠状态)
5:线程安全threadsafe

学习内容
一多线程

我们在之前,学习的程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计?要解决上述问题,咱们得使用多进程或者多线程来解决。

并发与并行

井发:指两个或多个事件在同一个时间段内发生。

并行:指两个或多个事件在同一时刻发生(同时发生)。

在操作系统中,安装了多个程序,并发指的是在一-段时间内宏观上有多个程序同时运行,这在单CPU系统中,每时刻只能有-道程序执行,即微观上这些程序

是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。

而在多个CPU系统中,则这些可以并发执行的程序便可以分配到多个处理器上(CPU) .实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程

序这样多个程序便可以同时执行。目前电脑市场上说的多核CPU.便是多核处理器,核越多,并行处理的程序越多,能大大的提高电脑运行的效率。

注意:单核处理器的计算机肯定是不能并行的处理多个任务的,只能是多个任务在单个CPU上并发运行。同理线程也是一样的, 从宏观角度上理解线程是并

行运行的,但是从微观角度上分析却是串行运行的,即一个线程一个线程的去运行, 当系统只有一个CPU时, 线程以某种顺序执行多个线程,我们把这种情况称之为线程调度。

线程与进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间, 一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运

行程序的基本单位;系统运行一个程序即是一 个进程从创建、 运行到消的过程。

线程: 线程是进程中的一 个执行单元,负责当前进程中程序的执行, 一个进程中至少有一 个线程。一个进程中是可以有多个线程的, 这个应用程序也可以称之为多线程程序。

简而言之: 一个程序运行后至少有一个进程, 一个进程中可以包含多个线程

我们可以再电脑底部任务栏,右键—>打开任务管理器可以查看当前任务的进程

线程调度:

分时调度

所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。

抢占式调度

优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性), Java便用的为抢占式调度。
抢占式调度详解

大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我们上课一边使用编辑器,- 边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是在同时运行,“感觉这些软件好像在同一时刻运行着”。

实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。

其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。
创建线程类

Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即-段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建并启动多线程的步骤如下:

  1. 定义Thread类的子类,并重写该类的run(方法, 该run0)方法的方法体就代表了线程需 要完成的任务因此把run)方法称为线程执行体。

2.创建Thread子类的实例,即创建了线程对象

3.调用线程对象的star()方法来启动该线程

创建线程方式二

采用java.lang . Runnable也是非常常见的一-种,我们只需要重写run方法即可。步骤如下:

1.定义Runnable接口的实现类,并重写该接口的run()方法,该run(方法的方法体同样是该线程的线程执行体。2.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象, 该Thread对象才是真正的线程对象。

3.调用线程对象的start()方法来启动线程。

二:Thread类和Runnable接口
thread类
Java中,创建线程的方法有两种:一是通过继承线程类Thread来创建线程;二是建立一个实现Runnable接口的类。

Runnable接口
从 NEW 到 RUNNABLE 状态

​Java 刚创建出来的 Thread 对象就是 NEW 状态,而创建 Thread 对象主要有两种方法。一种是继承 Thread 对象,重写 run() 方法。示例代码如下:

MyThread myThread = new MyThread();

另一种是实现 Runnable 接口,重写 run() 方法,并将该实现类作为创建 Thread 对象的参数。示例代码如下:

// 实现 Runnable 接口

class Runner implements Runnable {
@Override

public void run() {
// 线程需要执行的代码

}

}

// 创建线程对象

Thread thread = new Thread(new Runner());
步骤如下:1.定义类实现Runnable接口

2.覆盖Runnable接口中的run方法(将线程要运行的代码存放在run方法)

3.通过Thread类建立线程对象

4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数

(因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法 ,就必须明确改run方法所属的对象)

5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法

和继承Thread的实现多线程的区别如下:

1.避免了单继承的局限性(在定义线程是建议使用Runnable接口实现)

2.存储位置不同(继承方式:线程代码存放Thread子类的方法中

实现Runnable 线程代码存放在接口的子类的run方法中

三: 主线程与线程的生命周期
通用的线程生命周期基本上可以用下图这个“五态模型”来描述。这五态分别是:初始状态、可运行状态、运行状态、休眠状态和终止状态。

四:线程状态控制方法(sleep休眠状态)
sleep方法是Thread类中的一个静态方法,当一个执行中的线程调用了Thread的sleep方法之后,调用线程会暂时让出指定时间的执行权,这期间不参与CPU的调度,但是该线程所拥有的监视器资源,比如锁还是持有且不让出的。指定的睡眠时间到了之后,sleep函数会正常返回,线程就处于就绪状态,然后参与CPU调度,获取到CPU的资源后就可以运行了。

五:线程安全threadsafe
线程之间存在“竞争条件”,作用于同一个mutable数据上的多个线程,彼此之间存在对该数据的访问竞争并导致interleaving,导致post-condition可能被违反,这是不安全的。
线程安全:ADT或方法在多线程中要执行正确。
要做到:不违反spec,保持RI。与多少处理器,如何调度线程无关,不需要在spec中强制要求client满足某种“线程安全”的义务。

例如:Iterator就不是线程安全的,因为你不能在迭代遍历的时候改变collection。

保证线程安全,有四种策略:

(1)限制数据共享(Confinement)

(2)共享不可变数据(Immutability)

(3)共享线程安全的可变数据(Threadsafe data type)

(4)同步机制(Synchronization)

使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
06-03
这里是使用 Python 的 PyMySQL 完成上述任务的代码: ```python import pymysql # 连接数据库 conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='test') # 创建游标 cur = conn.cursor() # 创建 users 表 cur.execute(''' CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(20), age INT ) ''') # 创建 orders 表 cur.execute(''' CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATE, amount INT, user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) ) ''') # 插入数据 users_data = [ (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28) ] orders_data = [ (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4) ] for user in users_data: cur.execute('INSERT INTO users VALUES (%s, %s, %s)', user) for order in orders_data: cur.execute('INSERT INTO orders VALUES (%s, %s, %s, %s)', order) # 提交事务 conn.commit() # 查询语句 # 1. 查询订单总金额 cur.execute('SELECT SUM(amount) FROM orders') print(cur.fetchone()[0]) # 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 cur.execute('SELECT ROUND(AVG(age), 2) FROM users') print(cur.fetchone()[0]) # 3. 查询订单总数最多的用户的姓名和订单总数。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_orders DESC LIMIT 1 ''') print(cur.fetchone()) # 4. 查询所有不重复的年龄。 cur.execute('SELECT DISTINCT age FROM users') print([row[0] for row in cur.fetchall()]) # 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 cur.execute('SELECT SUM(amount) FROM orders WHERE order_date BETWEEN "2021-09-01" AND "2021-09-04"') print(cur.fetchone()[0]) # 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id WHERE age <= 25 GROUP BY users.id ORDER BY total_orders DESC ''') print(cur.fetchall()) # 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 3 ''') print(cur.fetchall()) # 8. 查询订单总金额最大的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 1 ''') print(cur.fetchone()) # 9. 查询订单总金额最小的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount ASC LIMIT 1 ''') print(cur.fetchone()) # 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 cur.execute('SELECT * FROM users WHERE name LIKE "%李%" ORDER BY name ASC') print(cur.fetchall()) # 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 cur.execute('SELECT * FROM users WHERE age > 20 ORDER BY age DESC LIMIT 5') print(cur.fetchall()) # 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC ''') print(cur.fetchall()) # 关闭游标和连接 cur.close() conn.close() ``` 注意:在运行代码之前,需要先安装 PyMySQL 模块,可以使用以下命令进行安装: ``` pip install pymysql ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值