目录
一、多线程
1.线程与进程
线程是程序中⼀个单⼀的顺序控制流程。进程内有⼀个相对独⽴的、可调度的执⾏单元,是系统独⽴调 度和分派CPU的基本单位指令运⾏时的程序的调度单位。在单个程序中同时运⾏多个线程完成不同的⼯ 作,称为多线程。
进程:进程指正在运⾏的程序。确切的来说,当⼀个程序进⼊内存运⾏,即变成⼀个进程,进程是处于 运⾏过程中的程序,并且具有⼀定独⽴功能。
JVM的启动是多线程的吗?
JVM启动⾄少启动了垃圾回收线程和主线程,所以是多线程的。
2.并发与并行
并发: 是当有多个线程在操作时,如果系统只有⼀个CPU,则它根本不可能真正同时进⾏⼀个以上的线程, 它只能把CPU运⾏时间划分成若⼲个时间段,再将时间段分配给各个线程执⾏,在⼀个时间段的线程代 码运⾏时,其它线程处于挂起状。这种⽅式我们称之为并发(Concurrent)。 如果⽤⼀台电脑我先给甲发个消息,然后⽴刻再给⼄发消息,然后再跟甲聊,再跟⼄聊。这就叫并发。
并⾏: 当系统有⼀个以上CPU时,则线程的操作有可能⾮并发。当⼀个CPU执⾏⼀个线程时,另⼀个CPU可 以执⾏另⼀个线程,两个线程互不抢占CPU资源,可以同时进⾏,这种⽅式我们称之为并 ⾏(Parallel)。 ⽐如我跟两个⽹友聊天,左⼿操作⼀个电脑跟甲聊,同时右⼿⽤另⼀台电脑跟⼄聊天,这就叫并 ⾏。
区别: 并发和并⾏是即相似⼜有区别的两个概念, 并⾏是指两个或者多个事件在同⼀时刻发⽣; ⽽并发是指两个或多个事件在同⼀时间间隔内发⽣。
3.程序运行原理
1.分时调度
所有线程轮流使⽤ CPU 的使⽤权,平均分配每个线程占⽤ CPU 的时间。
2.抢占式调度
优先让优先级⾼的线程使⽤ CPU,如果线程的优先级相同,那么会随机选择⼀个(线程随机性),Java 使⽤的为抢占式调度。
3.抢占式调度详解
⼤部分操作系统都⽀持多进程并发运⾏,现在的操作系统⼏乎都⽀持同时运⾏多个程序。⽐如:现在我 们上课⼀边使⽤编辑器,⼀边使⽤录屏软件,同时还开着画图板,dos窗⼝等软件。此时,这些程序是 在同时运⾏,"感觉这些软件好像在同⼀时刻运⾏着"。 实际上,CPU(*处理器)使⽤抢占式调度模式在多个线程间进⾏着⾼速的切换。对于CPU的⼀个核⽽ ⾔,某个时刻,只能执⾏⼀个线程,⽽ CPU的在多个线程间切换速度相对我们的感觉要快,看上去就 是在同⼀时刻运⾏。 其实,多线程程序并不能提⾼程序的运⾏速度,但能够提⾼程序运⾏效率,让CPU的使⽤率更⾼。
4.创建线程的方式
⽅式1,继承Thread线程类
步骤
1, ⾃定义类继承Thread类
2, 在⾃定义类中重写Thread类的run⽅法
3, 创建⾃定义类对象(线程对象)
4, 调⽤start⽅法,启动线程,通过JVM,调⽤线程中的run⽅法
⽅式2,实现Runnable接⼝
步骤
1, 创建线程任务类 实现Runnable接⼝
2, 在线程任务类中 重写接⼝中的run⽅法
3, 创建线程任务类对象
4, 创建线程对象,把线程任务类对象作为Thread类构造⽅法的参数使⽤
5, 调⽤start⽅法,启动线程,通过JVM,调⽤线程任务类中的run⽅法
5.线程生命周期图
6.线程池
在java中,如果每个请求到达就创建⼀个新线程,开销是相当⼤的。在实际使⽤中,创建和销毁线程 花费的时间和消耗的系统资源都相当⼤,甚⾄可能要⽐在处理实际的⽤户请求的时间和资源要多的多。 除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在⼀个jvm⾥创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”⽽导致系统资源不⾜。为了防⽌资源不⾜,需要采 取⼀些办法来限制任何给定时刻处理的请求数⽬,尽可能减少创建和销毁线程的次数,特别是⼀些资源 耗费⽐较⼤的线程的创建和销毁,尽量利⽤已有对象来进⾏服务。
线程池主要⽤来解决线程⽣命周期开销问题和资源不⾜问题。通过对多个任务重复使⽤线程,线程创建 的开销就被分摊到了多个任务上了,⽽且由于在请求到达时线程已经存在,所以消除了线程创建所带来 的延迟。这样,就可以⽴即为请求服务,使⽤应⽤程序响应更快。另外,通过适当的调整线程中的线程 数⽬可以防⽌出现资源不⾜的情况。
【线程池的作⽤?】
1、限定线程的个数,不会导致由于线程过多导致系统运⾏缓慢或崩溃
2、线程池不需要每次都去创建或销毁,节约了资源、
3、线程池不需要每次都去创建,响应时间更快
7.线程安全
//方式1: 同步代码块 -同步代码块的锁对象可以是任意的对象
synchronized (锁对象){
可能产生线程安全问题的代码
}
//方式2: 同步方法-同步方法中的锁对象是
this public synchronized void method(){
可能产生线程安全问题的代码
}
//方式3: 静态同步方法- 静态同步方法中的锁对象是
类名.class public synchronized void method(){
可能产生线程安全问题的代码
}
8.等待唤醒机制
线程之间的通信:多个线程在处理同一个资源,但是处理的动作 (线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。 等待唤醒机制所涉及到的方法:
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这 些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。
二、网络编程
1.网络通信协议
⽹络通信协议有很多种,⽬前应⽤最⼴泛的是TCP/IP协议(Transmission Control Protocol/Internet Protocol传输控制协议/IP协议),它是⼀个包括TCP协议和IP协议, UDP(User Datagram Protocol)协议和其它⼀些协议的协议组,在学习具体协议之前⾸先了解⼀ 下TCP/IP协议组的层次结构。
在进⾏数据传输时,要求发送的数据与收到的数据完全⼀样,这时,就需要在原有的数据上添加很多信 息,以保证数据在传输过程中数据格式完全⼀致。
TCP/IP协议中的四层分别是应⽤层、传输层、⽹络层和链路层,每层分别负责不同的通信功 能,接下来针对这四层进⾏详细地讲解。
链路层:链路层是⽤于定义物理传输通道,通常是对某些⽹络连接设备的驱动协议,例如针对光纤、⽹ 线提供的驱动。
⽹络层:⽹络层是整个TCP/IP协议的核⼼,它主要⽤于将传输的数据进⾏分组,将分组数据发送到⽬ 标计算机或者⽹络。
传输层:主要使⽹络程序进⾏通信,在进⾏⽹络通信时,可以采⽤TCP协议,也可以采⽤UDP协议。
应⽤层:主要负责应⽤程序的协议,例如HTTP协议、FTP协议等。
2UDP协议
UDP是⽆连接通信协议,即在数据传输时,数据的发送端和接收端不建⽴逻辑连接。简单来说,当⼀台 计算机向另外⼀台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在 收到数据时,也不会向发送端反馈是否收到数据。
由于使⽤UDP协议消耗资源⼩,通信效率⾼,所以通常都会⽤于⾳频、视频和普通数据的传输例如视频 会议都使⽤UDP协议,因为这种情况即使偶尔丢失⼀两个数据包,也不会对接收结果产⽣太⼤影响。
但是在使⽤UDP协议传送数据时,由于UDP的⾯向⽆连接性,不能保证数据的完整性,因此在传输重要 数据时不建议使⽤UDP协议。
3.TCP协议
TCP协议是⾯向连接的通信协议,即在传输数据前先在发送端和接收端建⽴逻辑连接,然后再传输数 据,它提供了两台计算机之间可靠⽆差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由 客户端向服务端发出连接请求,每次连接的创建都需要经过"三次握⼿"。
第⼀次握⼿,客户端向服务器端发出连接请求,等待服务器确认,
第⼆次握⼿,服务器端向客户端回送⼀个响应,通知客户端收到了连接请求,
第三次握⼿,客户端再次向服务器端发送确认信息,确认连接。
4.UDP程序交互流程
> 发送端
1,创建DatagramSocket对象
2,创建DatagramPacket对象,并封装数据
3,发送数据
4,释放流资源
> 接收端
1,创建DatagramSocket对象
2,创建DatagramPacket对象
3,接收数据存储到DatagramPacket对象中
4,获取DatagramPacket对象的内容
5,释放流资
5.TCP程序交互流程
<1> 客户端
1,创建客户端的Socket对象
2,获取Socket的输出流对象
3,写数据给服务器
4,获取Socket的输⼊流对象
5,使⽤输⼊流,读反馈信息
6,关闭流资源
<2> 服务器端
1,创建服务器端ServerSocket对象,指定服务器端端⼝号 2,开启服务器,等待着客户端Socket对象的连接,如有客户端连接,返回客户端的Socket对象
3,通过客户端的Socket对象,获取客户端的输⼊流,为了实现获取客户端发来的数据
4,通过客户端的输⼊流,获取流中的数据
5,通过客户端的Socket对象,获取客户端的输出流,为了实现给客户端反馈信息
6,通过客户端的输出流,写数据到流中
7,关闭流资源
三、数据库表常用指令
1、查询所有的数据库表
show databases;
2、使用哪个数据库表
use 数据库名;
3、创建数据库表
create table <表名>(
<字段名1> <数据类型> [列级别约束条件][默认值],
<字段名2> <数据类型> [列级别约束条件][默认值],
<字段名3> <数据类型> [列级别约束条件][默认值],
...
)[engine=引擎][default chaset=字符编码];
注意:
<>中的内容是必须有的,[]可以有也可以没有
最有一个字段后面不加","
[]部分如果没有设置,那么mysql会使用默认的设置
create table student(
-> sid int,
-> sname varchar(15),
-> age int
-> );
注意:
1、sql语法不跟java一样严格区分大小写,sql语句大写小写都行,按惯例,所有的sql语句都是大写的,因为小写发送给服务器进行运行的时候,也会先转换成大写再执行
2、严格语法中,数据库名和字段名需要使用反单引号括起来
3、如果数据库名和表名有多个单词组成,惯例使用"下划线命名法"
约束:
1、非空(not null)约束
是一个列级别的约束,要求所限定的列不允许放空值进来
create table 表名(
字段名 数据类型 not null,
...
);
create table teacher(
-> tid int,
-> tname varchar(15),
-> tsex varchar(2),
-> phone int not null
-> );
2、唯一性约束,是一个列级别的约束,设定的列不运行插入重复的值
create table 表名(
字段名 数据类型 unique,
...
);
create table a(
-> id int not null,
-> name varchar(20) unique not null,
-> pwd varchar(20)
-> );
3、默认值(default)约束
默认值越是,是一个列级别的约束,所限定的列,当没有插入值的时候,给定一个默认值
create table 表名(
字段名 数据类型 default 具体的值,
...
);
create table tb_02(
-> id int not null,
-> uname varchar(20) unique not null,
-> place varchar(20) default 'wh'
-> );
into tb_02(id,uname) values(1,'zhangsan');
insert into tb_02(id,uname,place) values(2,'lisi','sh');
4、主键(primary key)约束
主键约束是一个表级别的约束,它等价于 非空 + 唯一约束
它要求所限定的列,非空且唯一
一个表中只能有一个主键
主键约束分为两种:
单主键:通常直接在列的尾部进行声明
create table 表名(
字段名 数据类型 primary key,
...
);
联合主键:主键设计两个列或者两个以上的列,多个列作为主键
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型,
...
primary key(字段名1,字段名2,字段名3...)
);
mysql> create table tb_stu(
-> stuId int primary key, -- 设置主键
-> stuName varchar(20) not null
-> );
mysql> create table tb_cs(
-> sid int,
-> cno int,
-> score double,
-> primary key(sid,cno) -- 设置联合主键
-> );
-- 表没有创建主键添加主键
mysql> create table tb_03(
-> id int,
-> name varchar(20) not null
-> );
mysql> alter table tb_03 add primary key(id);-- 添加主键
mysql> alter table tb_03 drop primary key;-- 删除主键
5、外键(foreign key)约束
外键约束,是一种表级别的约束,他用于表示被它修饰的列中的数据,需要参考另一张表的某一个列中的值
create table a表(
...
字段名 类型 references b表(某个字段)
...
);
create table a表(
...
...
constraint 约束名 foreign key a表中的字段名 references b表(某个字段)
);
四、数据库表的相关操作
-- 如何查看表结构
-- 查看表的字段信息
desc 表名;
describe 表名;
-- 查看建表语句
show create table 表名;
-- 修改表中的原数据
-- 添加主键约束
alter table 表名 add [constraint 主键约束名] primary key(主键字段);
-- 删除外键约束
alter table 表名 drop foreign key 外键约束名;
-- 创建好表之后想要添加外键连接
alter table 表名 add constraint 外键约束名 FOREIGN key(外键字段名) REFERENCES 主表(关联字段名);
-- 删除主键约束
alter table 表名 drop primary key;
-- 创建好表之后想要添加列
alter table 表名 add 字段名 字段数据类型;
-- 修改列类型,长度,以及约束
alter table 表名 modify 列名 数据类型(长度) 约束;
-- 修改列的名称
alter table 表名 change 旧列名 新列名 数据类型(长度)约束;
-- 删除列
alter table 表名 drop 列名;
-- 给表进行重命名
rename table 表名 to 新表名;
-- 修改表的字符编码
alter table 表名 character set 字符编码;
-- 删除表
drop table if exists 表名; -- 表中的数据和表都不在了
-- 删除表中的数据,数据不在了,表还在
truncate table 表名;
delete from 表名;
五、数据库表中的数据操作
①数据库中的增删改操作
show DATABASES;
use test_01;
-- 增删改操作被称为DML语句
-- DML语句用于操作数据库表和视图的数据
-- insert 向表中添加数据
-- update 修改表中的数据
-- delete 删除表中的数据
-- insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3...);
-- 要给几个字段赋值,就写几个字段,默认的就不要写了,要做到一一对应
-- 添加一条信息
insert into tb_dept(deptId,deptName) VALUES(1,'研发部');
-- 添加多条信息
insert into tb_dept(deptId,deptName) VALUES(2,'行政部'),(3,'后勤部'),(4,'保安部');
-- 如果没有指定列名,默认插入所有的信息
insert into tb_emp VALUES(1,'李小龙','男',3200,4);
insert into tb_emp(empName,empSex,empSal) VALUES('狄仁杰','男',20000);
-- update语句
-- update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3,...WHERE 条件表达式;
-- 凡是符合where子句的都会被更新
-- 没有where子句,修改所有的行的数据
-- 部门编号为1的员工的工资加10%
UPDATE tb_emp set empSal=empSal * 1.1 where did = 1;
-- 将所有的员工的工资增加原来的50%
UPDATE tb_emp set empSal=empSal * 1.5;
-- 修改表中狄仁杰的部门号为
UPDATE tb_emp set did = 1 where empName = '狄仁杰';
-- 修改id为1的员工的姓名为吴亦凡
UPDATE tb_emp set empName = '吴亦凡',empSal = 2 where empId = 1;
-- 将2号部门中的男员工的工资加2000
UPDATE tb_emp set empSal = empSal + 2000 where did = 2 and empSex = '男';
-- 如果一个人部门号是4,或者工资小于100,就将工资设为0
UPDATE tb_emp set empSal = 0 where did = 4 or empSal < 100;
-- delete语句
-- delete from 表名 where 条件表达式;
-- 凡是符合条件的行都会被删除,如果没有where子句,则删除表中所有数据
-- 清空表的数据,表还在
-- drop table 表名; -- 删除表
-- truncate table 表名;-- 快速删除表中的数据,表还在
-- 删除两个元素
delete from tb_emp where empName in('吴亦凡','孙悟空');
delete from tb_emp where empName = '曾志伟' or empName = '狄仁杰';
-- 删除所有元素
delete from tb_emp;
select * from tb_emp;
②查询语句
-- 查询语句
-- 使用最频繁的sql语句就是select,其用途就是从一个或者多个表中检索信息
-- select 是DQL语句
-- 查询单列
-- select 列名 from 表名;
-- 从指定的表中查询表出单个指定的列的信息
select empName from tb_emp;
-- 查询多列
-- select 列名1,列名2,...from 表名;
-- 从指定的表中查询出多个指定的列的数据
SELECT empName,empSex,empSal from tb_emp;
-- 查询所有的列
-- select * from 表名;
-- * 是一个通配符
-- 在实际工作中,最好不要使用*,因为查询出来不需要的列通常会降低查询的效率
select * from tb_dept;
-- 使用完全限定的表名
-- 表的完全限定名: 库名.表名;
-- 列的完全限定名: 表名.列名;
-- 对查询到的数据进行排序
-- select 字段名1,字段名2... from 表名 order by 列名;
-- 以升序的形式进行排序
-- 如果不进行排序,则数据获取的时候以它们插入的时候的顺序取出
-- 如果需要排序,就使用order by
select empName,empSal from tb_emp ORDER BY empSal;
-- 这是以降序的形式进行排序
select * from tb_emp ORDER BY empSal DESC;
-- DESC 降序
-- ASC 升序 默认
-- 按多列进行排序
-- select 字段名1,字段名2...FROM 表名 ORDER BY 列名1,列名2...;
-- 以第一个列进行排序,如果出现相等,则会以第二个列进行参考,一次类推
select * from tb_emp ORDER BY empSal,empId;
-- 过滤数据where
-- select 字段名1,字段名2,...from 表名 where 过滤条件
-- where 子句 可以使用运算符:
-- = 等于
-- != <> 不等于
-- < 小于 > 大于 <= 小于等于 >= 大于等于
-- between ... AND...
-- 日期也可以使用这些符号来进行表示,但是有格式要求'yyyy - MM - dd'
-- 日期要使用''单引号括起来,必须给定合法的格式'yyyy -MM - dd'
-- 当某一列没有任何值的时候,称之为NULL
-- 注意:没有值,不是0,空字符串,空白字符串
-- is null 判断是否为空 is not null 非空
-- 高级数据过滤
-- select * from 表名 where 过滤条件1 or 过滤条件2; -- 或者
-- select * from 表名 where 过滤条件1 and 过滤条件2; -- 并且
-- in 运算符可以替换or
-- select * from 表名 where in(值1,值2......); -- 或者
-- in运算符要比or运算符效率高,in 里面可以写另外一条sql语句
-- SELECT * FROM 表名 where not 过滤条件; -- 取反
-- 1、查询单列
select empName from tb_emp;
-- 2、查询多列
select empName,empSal from tb_emp;
-- 3、查询所有信息
select * from tb_emp;
-- as e 给表取一个别名
-- 表名.列名
select e.empId,e.empName,e.empSal,e.empSex,e.did from tb_emp as e;
-- 4、按照工资进行排序,如果工资相同就按照姓名排序
select * from tb_emp ORDER BY empSal DESC, empName ASC;
-- 5、查询工资高出10000的员工的姓名和部门编号
SELECT empName,did from tb_emp where empSal > 10000;
-- 6、查工资在5000 ~ 10000之间的员工的信息
SELECT * FROM tb_emp where empSal >= 5000 and empSal <= 10000;
SELECT * FROM tb_emp where empSal BETWEEN 5000 and 10000;
-- 7、查询不是1号部门的员工的信息
SELECT * from tb_emp where did <> 1;
SELECT * from tb_emp where did != 1;
SELECT * from tb_emp where not did = 1;
-- 8、查询没有部门信息的员工
select * from tb_emp WHERE did is null;
select * from tb_emp WHERE did is not null;
-- 9、模糊查询
-- select * from 表名 where 列名 like 通配符字符串;
-- %匹配出现任意次数的任意字符 %也可以匹配0个字符 %不能匹配null
-- _只能匹配一个字符
-- 查询所有姓李的人的信息
select * from tb_emp WHERE empName like '李%';
select * from tb_emp WHERE empName like '李_';
use test_01;
-- 有时操作数据库的目的是用于数据的汇总
-- 获取行数
-- 可以获取某列中的最大值,最小值,平均数
-- 标准的sql语句中提供了5个常用的聚合函数
-- avg() 求某列的平均值,avg()函数获取的时候不考虑null值
-- count() 某列的行数
-- count(*) 会计算所有的行,包括空行
-- count(列名) 只会读取计算指定列中有值的行,不会考虑null行
-- max()某列中的最大值
-- max(列名) 不统计null行
-- min()某列中的最小值
-- min(列名) 不统计null行
-- sum()将某列的值进行求和
-- sum(列名) 不统计null行
-- 分组查询
-- 在没有指定分组查询之前,所有查询的数据都默认在同一个组里面
-- 聚合函数都是对这一组信息进行计算和处理
-- 我们可以使用group by进行分组处理
-- 分别查找某一个部门有多少人
select did,count(*) from tb_emp GROUP BY did;
-- group by 和 select一样,可以通过逗号分隔指定多的列
-- 还可以按照多个列进行分组
select did,count(*) from tb_emp GROUP BY did,empName;
-- 使用分组和聚合函数的时候,select子句,只能存在三种元素
-- 常数
-- 聚合函数
-- group by 子句中的列名 不能使用列的别名
-- having分组条件
-- where 子句,用于指定行所对应的条件
-- having 子句,用于指定组所有的条件
-- having 是分组以后,对分组后的结果进行的再一次过滤
select did,count(*) from tb_emp GROUP BY did having count(*) >= 2;
select * from tb_emp where empSal = (select MAX(empSal) from tb_emp);
-- limit子句
-- 分页
-- 从下标为2的元素开始,往后数3个
select * from tb_emp LIMIT 4,2;
select * from tb_emp;
-- totalSize = 8 总记录条数
-- pageSize 每页显示多少数据
-- totalPage = 总记录条数 / 每页的数据条数
-- 如果有余数就 + 1
-- 如果没有余数,就是当前的总页数
-- LIMIT pageSize * (pageNum - 1),pageSize