# LearningJava **Repository Path**: Mark--Zhang/learning-java ## Basic Information - **Project Name**: LearningJava - **Description**: Java学习笔记 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-10-17 - **Last Updated**: 2024-10-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 第一章、Java基础知识 #### 1.1、 运行原理 Java语言既是编译型语言,又是解释性语言,Java语言的运行原理: .java文件 -> 编译器 -> .class文件 -> 解释器(JVM) -> 机器码 我们直接下载的是JDK(Java Develop Kit),其中包含了编译等开发工具和JRE,JRE包含了JVM,JVM包含了解释器。 #### 1.2、Java语言的特点 1. 类型自动转换的规则:当容量小的数据类型与容量大的数据类型做运算时,结果自动提升为容量大的数据类型。 2. 静态方法或者静态代码块中只能调用静态的成员变量或者静态的成员方法,不能调用非静态的成员变量或者非静态的成员方法,静态变量在类加载的时候就已经存在了,而非静态变量是在类实例化的时候才会存在。 ![img.png](img/img_23.png) 2. 三目运算符的数据类型自动提升规则:当第二个和第三个操作数类型不一样时,将会发生数据类型的自动提升。 #### 1.3、Java的内存分配机制 Java的内存分配机制分为栈内存和堆内存,其中栈内存用于存储局部变量,堆内存用于存储new出来的对象。 #### 1.4、Java面向对象编程 面向对象的三个特性是:封装、继承、多态。 封装的基本单位是对象。 方法的重载:不同的方法名字相同,但是参数列表不同。注意,如果仅有返回值不同,那么就不是重载,相反是语法错误。 常见的缺省值:引用的缺省值是null,double的缺省值是0.0,byte的缺省值是0,boolean的缺省值是false,char的缺省值是'\u0000',int的缺省值是0,short的缺省值是0,long的缺省值是0L,float的缺省值是0.0f。 构造方法:通常,构造方法没有返回值 #### 1.5、this引用 this指向的是实例化对象,this()指向的是构造方法。 #### 1.6、Java中的包 Java中的包是用来管理类的,包的作用是为了防止类名冲突,同时也是为了方便管理类。 包的声明必须放在源文件的第一行,包的声明语句是package 包名;。 包的命名规则是:全部小写,多级包用.分隔,一般是公司域名的倒序。 包的导入规则如下: 1. 使用完整类名或import导入类; 2. 一条import语句只能导入一个包; 3. 使用*可以导入一个包中的所有类; 4. java.lang包是Java核心包,不需要导入; 5. 如果导入的不同包中有相同的类名,会出现歧义。 #### 1.7、Java中的访问权限 Java中的访问权限分为四种:public、protected、default、private。 ![img_1.png](img/img_21.png) #### 1.8、类成员变量 类成员变量的作用域是整个类,可以在类中的任何地方使用,类成员变量的生命周期是整个程序的运行期间,用static修饰的类成员变量是静态成员变量,用final修饰的类成员变量是常量。 静态成员变量所有当前类创建的对象都能访问。 ### 第二章、Java数据结构与算法入门 通常来说,在Collection接口中有List、Queue和Set三个抽象类,在Map接口中有SortedMap抽象类。 最终的实现类包括Vector->stack;ArrayList;LinkList;PriorityQueue;TreeSet;HashSet;Hashmap;TreeMap。 ![img.png](img/img_11.png) #### 2.0 Collection接口介绍 Collection接口常用方法 | 方法名称 | 用处 | |----------|------------| | put() | 添加元素 | | get() | 获取键值对应的元素值 | | remove() | 删除对应元素 | | clear() | 清空所有元素 | #### 2.1 list接口 Java中的栈和队列使用方法总结 1. Stack ![img.png](img/img_12.png) 2. Queue ![img_1.png](img/img_13.png) ##### 2.1.1 ArrayList类 ##### 2.1.2 CircleList类 ##### 2.1.3 Vector类 #### 2.2 Set接口 常用的方法: |方法|用处| |----|----| |add()|添加元素| |Iterator iterator()|返回迭代器| |int size()|返回set中的元素个数| ##### 2.2.1 HashSet类 #### 2.3 Queue接口 ##### 2.3.1 简单队列 ##### 2.3.1 优先队列 优先队列底层实现就是堆,也是一颗完全二叉树,常用的操作如下: 1. 建堆,时间复杂度是O(n * log(n)) 2. 向下调整,将最大的节点依次向下调整 #### 2.4 Map接口 Map的底层实现就是红黑树 常见的使用方法(除了Collection接口所共有的以外): |方法|用处| |---|---| |K getKey()|返回key| |V getvalue()|返回Value| |getOrDefault(Object K,V defaultValue)|返回key对应的value, key不存在就返回默认值| |Set>entrySet()|返回所有的映射关系| |boolean containsKey(Object key)|判断是否包含key| |boolean containsValue(Object value)|判断是否包含value| !!!注意:Map是一个接口,不能直接实例化对象!需要通过Treemap或者HashMap来实例化对象。 当存入数据的时候,Key必须是唯一的而且不能少但是value可以为空。 ##### 2.4.1 HashMap HashMap中每个元素是一对数据,其中K是键值,V是值,K必须唯一,当添加一个元素的时候要根据哈希函数计算存储的位置,其内核是使用红黑树实现的。 ![img_3.png](img/img_15.png) 常用HashMap方法总结: | 方法名称 | 用处 | |----------|------------| | put() | 添加元素 | | get() | 获取键值对应的元素值 | | remove() | 删除对应元素 | | clear() | 清空所有元素 | ##### 2.4.2 TreeMap #### 2.5 排序算法 https://blog.csdn.net/qq_43794633/article/details/121612149#:~:text=%E5%8D%81%E5%A4%A7%E7%BB%8F%E5%85%B8%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%EF%BC%88Java%E5%AE%9E%E7%8E%B0%EF%BC%89%201%201%E3%80%81%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F%EF%BC%88Bubble%20Sort%EF%BC%89%202%202%E3%80%81%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F%EF%BC%88Selection%20Sort%EF%BC%89%203,7%207%E3%80%81%E5%A0%86%E6%8E%92%E5%BA%8F%EF%BC%88Heap%20Sort%EF%BC%89%208%208%E3%80%81%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F%EF%BC%88Counting%20Sort%EF%BC%89%20More%20items ![img_2.png](img/img_14.png) 具体代码实现在项目工程中实现。 ### 第三章、Java中的IO流 在Java中,流是有方向的,以当前程序位基准,输入程序的流为输入流,输出程序的流是输出流。 使用流进行数据的输入输出的过程大致如下: 输入: 1. 建立适当的输入流类对象,建立连接。 2. 调用相应的read()方法从文件中读取数据。 3. 关闭流,释放相关的系统资源。 输出: 1. 建立适当的输出流类对象,建立简介。 2. 调用相应的write()方法输出数据。 3. 关闭流,释放相应的系统资源。 #### 3.1 字节流 字节流是指以字节流为传输单位的数据流,字节流主要用于处理二进制文件,例如图片、视频、音频等文件。 InputStream和OutputStream是字节流的基类,其中InputSream是输入流,OutputSream是输出流;注意,这两个类都是抽象类,不能直接实例化对象。 常用的字节流有FileInputStream、FileOutputStream、BufferedInputStream、BufferedOutputStream、DataInputStream、DataOutputStream、ObjectInputStream、ObjectOutputStream等。 ##### 3.1.1 FileInputStream FileInputStream是InputStream的子类,用于读取文件中的数据,常用的方法有read()、read(byte[] b)、read(byte[] b, int off, int len)、close()等。 ##### 3.1.2 FileOutputStream FileOutputStream是OutputStream的子类,用于向文件中写入数据,常用的方法有write(int b)、write(byte[] b)、write(byte[] b, int off, int len)、close()等。 #### 3.2 字符流 字符流是以字符为传输单位的数据流,字符流主要用于处理文本文件,例如txt文件。 Reader和Writer是字符流的基类,其中Reader是输入流,Writer是输出流,注意,这两个类都是抽象类,不能直接实例化对象。 常用的字符流有FileReader、FileWriter、BufferedReader、BufferedWriter、PrintWriter等。 #### 3.3 文件类 File类是Java中用于表示文件或者目录的类,常用的构造方法有: 1. File(String pathname):根据指定的路径创建File对象 2. File(String parent, String child):根据指定的父路径和子路径创建File对象 3. File(File parent, String child):根据指定的父路径对象和子路径创建File对象 4. File(URI uri):根据指定的URI对象创建File对象 5. File(String pathname):根据指定的路径创建File对象 常用的方法有: 1. public boolean exists():判断文件或者目录是否存在 2. public boolean isFile():判断是否是文件 3. public boolean isDirectory():判断是否是目录 4. public String getAbsolutePath():获取绝对路径 5. public String getName():获取文件或者目录的名称 6. public long length():获取文件的长度 7. public String[] list():列出当前目录下的所有文件和目录名称 8. public boolean delete():删除文件或者目录 ##### 3.3.1 FileReader,文件字符输入流 FileReader是Reader的子类,用于读取文件中的数据,常用的方法有read()、read(char[] b)、read(char[] b, int off, int len)、close()等。 ##### 3.3.2 FileWriter,文件字符输出流 FileWriter是Writer的子类,用于向文件中写入数据,常用的方法有write(int b)、write(char[] b)、write(char[] b, int off, int len)、close()等。 常用方法: #### 3.4 实体流和装饰流 实体流是直接与数据源相连的流,装饰流是对实体流的包装,通过对实体流的包装,可以提供更加强大的功能。 常用的实体流有FileInputStream、FileOutputStream、FileReader、FileWriter等。 常用的装饰流有BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter等。 #### 3.5 缓冲流 缓冲流是对实体流的包装,通过对实体流的包装,可以提供更加强大的功能。 常用的缓冲流有BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter等。 #### 3.6 数据流 数据流是对实体流的包装,通过对实体流的包装,可以提供更加强大的功能,数据流属于装饰流,常用的数据流有DataInputStream、DataOutputStream等。 #### 3.7 对象流和对象序列化 对象序列化可以理解为将对象转换成易于存储和传输的字节序列的过程,具体实现形式就是调用Serializable接口。 对象流属于装饰流。 ##### 3.7.1 Serializable接口 Serializable接口是一个标记接口,没有任何方法,只是用来标记当前类可以被序列化。 当一个类实现了Serializable接口之后,在对象序列化的时候除了transient变量和static变量之外,其他的变量都会被保存起来。 如果想要自定义保存的类中的成员变量,需要实现Externalizable接口。 #### 3.8 标准输入输出流 标准输入输出流是Java中的特殊流,用于从键盘读取数据和向控制台输出数据。 常用的标准输入输出流有System.in、System.out、System.err。 #### 3.9 桥接流 桥接流是用来连接两个流的,常用的桥接流有InputStreamReader、OutputStreamWriter等。 #### 3.10 流的关闭 流的关闭是为了释放系统资源,常用的关闭方法有close()、flush()等。 在finally中关闭流的好处是不管程序是否出现异常,都可以保证流的关闭。 还有一种关闭流的方式是将资源的声明放在try后面的小括号中,这样就不用在finally中关闭流了,这种方式叫做try-with-resources。 | 方法名称 | 用处 | |-------------------------|---------------------------| | public String getName() | 返回文件或者目录的名称 | | public String[] list() | 列出当前目录下的所有文件和目录名称 | | public long length() | 返回文件的长度(字节数),如果是目录,返回值不确定 | #### 3.3 实体流和装饰流 #### 3.4 对象流和对象序列化 对象序列化可以理解为将对象转换成易于存储和传输的字节序列的过程,具体实现形式就是调用Serializable接口。 对象流属于装饰流。 ObjectOutputStream -> writeObject() ObjectInputStream -> readObject() 如果想要自定义保存的类中的成员变量,需要实现Externalizable接口。 ### 第四章、Java图形化界面 #### 4.1 AWT概述 - 常用的组件与容器 - 顶层容器:框架JFrame和对话框JDialog - 中间层容器:面板JPanel、滚动面板JScrollPane、工具栏JToolBar #### 4.2 JFrame常见的方法总结 | 方法名称 | 用处 | |-----------------------------------------------|-----------------| | public JFrame(String Title) | 构造方法,创建JFrame对象 | | public setSize(int width, int height) | 自定义大小 | | public setVisible(bool b) | 设置窗口可见度 | | public resizable(bool b) | 设置窗口是否用户可修改 | | public setLayout(LayoutManager manager) | 设置框架的布局管理器 | | public add(Component comp, Object constrains) | 将组件添加到容器中 | | public remove(Component comp) | 将特定组件删除 | #### 4.3 JPanel常用方法 | 方法名称 | 用处 | |---------------------------------------|--------------| | public JPanel(LayoutManager layout) | 创建有指定布局格式的面板 | | public setSize(int width, int height) | 设置组件大小 | | public setBorder(Border border) | 设置组件边框 | | public setBackground(color bg) | 设置背景色 | | public setForeground(color bg) | 设置前景色 | #### 4.4 JButton | 方法名称 | 用处 | |---------------------------------------|--------------| |public ImageIcon(String filename)|创建图标按钮| #### 4.5 JLabel JLabel一般用来显示文本或者图像 | 方法名称 | 用处 | |-----------------------------|------------| | public setText(String text) | 设置要显示的文本 | | public setIcon(Icon icon) | 设置标签要显示的图标 | #### 4.6 JTextField JTextField一般用来接受用户输入数据,同时也可以显示结果。 | 方法名称 | 用处 | |---------------------------------------------------|-------------| | public setTex(String s) | 设置文本框中的内容 | | public String getText() | 获取文本框中的内容 | | public void setEditable(bool b) | 设置文本框是否可以编辑 | | public void setHorizontalAlignment(int alignment) | 设置文本的水平对齐方式 | #### 4.7 JTable JTable一般用来显示表格数据,其中JTable的数据模型是TableModel,TableModel是一个接口,其中常用的方法有: | 方法名称 | 用处 | |---------------------------------------------------|-------------| | public int getRowCount() | 获取表格的行数 | | public int getColumnCount() | 获取表格的列数 | | public Object getValueAt(int row, int column) | 获取指定行列的值 | | public String getColumnName(int column) | 获取指定列的名称 | | public Class getColumnClass(int columnIndex) | 获取指定列的数据类型 | | public boolean isCellEditable(int rowIndex, int columnIndex) | 判断指定单元格是否可编辑 | 创建一个表格的顺序: 0. 创建两个Vector分别存储行和列的信息。 1. 定义一个DefaultTableModel,并导入提前声明好的行和列。 2. 创建一个JTable对象,并导入DefaultTableModel。 3. 创建一个JScrollPane对象,并导入JTable。 4. 如果要更新表格内容,使用UpdateUI()方法即可。 #### 4.7 布局管理器 布局管理器决定了各个组件在容器中的大小以及摆放位置。 1、流式布局管理器Flow 2、边界布局管理器Border 3、网络布局管理器Grid 4、网格组布局管理器 5、卡片布局管理器 调用方法(以流式布局管理器为例): | 方法名称 | 用处 | |---------------------------------------------------|------------------------| |public void setAlignment(int align)| 设置组件之间以及组建于容器边缘之间的水平间距 | #### *4.8 事件处理* 重点注意,在编写事件监听器接口的时候必须要记得实现方法!!!! | 事件类 | 事件监听器接口 | 事件监听器接口中的方法 | |------------|---------------------|-------------------------------------| | ActionEvent | ActionListener | void actionPerformed(ActionEvent e) | | ItemEvent | ItemListener | void itemStateChanged(ItemEvent e) | | KeyEvent | KeyListener | void keyTyped(KeyEvent e) | | | | void keyPressed(KeyEvent e) | | | | void keyReleased(KeyEvent e) | | MouseEvent | Mouselistener | void mouseClicked(MouseEvent e) | | | | void mouseClicked(MouseEvent e) | | | | void mousePressed(MouseEvent e) | | | | void mouseReleased(MouseEvent e) | | | | void mouseEntered(MouseEvent e) | | | | void mouseExited(MouseEvent e) | | | MouseMotionListener | void mouseDragged(MouseEvent e) | | | | void mouseMoved(MouseEvent e) | #### 4.9 内部类和匿名类以及lamda表达式 - 内部类:相当于是继承了所在外部类的所有private属性并有访问权限,内部类经常被用作监听器类! - 匿名类:直接使用new方法创建对象,不用先类,然后再实现。 - lamda表达式:(参数列表)->{方法体} #### 总结:创建图形用户界面的步骤 1. 创建界面,继承JFrame类 2. 定义控件,定义控件名称以及大小,同时添加到相应的面板中。 3. 设置控件组,实现控件的布局 3. 定义控件在界面中的位置,设置布局管理器 4. 设置控件的事件监听器,可以通过内部类、匿名类、lamda表达式来实现 5. 显示界面 ### 第五章、Java链接Mysql数据库 写在前面:由于Java中有Mysql数据库的封装库,所以这里仅仅就Mysql基础知识进行叙述,详细的知识点在数据库。 在数据库中打开数据库文件。。。 #### 5.1 连接方式以及步骤 1. 通过DeviceManager类连接数据库 2. 通过DataSource接口建立连接 创建数据库连接的步骤: 1. 使用Class.forname函数加载数据库驱动 2. 提供JDBC连接的数据库URL,可以是本地地址:端口;也可以是远程地址:端口 3. 调用DriverManager.getConnection(String url, String username, String password),建立数据库连接 执行SQL语句的步骤 1. 创建Statement语句对象,通过Statement stmt = conn.createStatement() 2. 执行SQL语句,通过rs = stmt.executeQuery(sql)语句来得到结果集 3. 处理结果集,通过while循环,逐行遍历结果集 4. 关闭数据库连接 DBMS:用于创建数据库的软件,数据库中数据以数据表的形式存储 #### 5.2 关系型数据库 ![img.png](img/img.png) #### 5.3 Sql语句 - 关键字建议使用大写,同时在使用的时候注意在最后加上分号,有一点要注意的就是字符串在SQL语句中使用的是两个单引号。 ![img_1.png](img/img_1.png) - 分类 - DDL:用于定义数据库对象 - DML:数据库操作语言,用来对数据库表中的数据进行增删改操作 - DQL:数据查询语句,用来查询数据库中表的记录 - DCL:数据控制语言,用来创建数据库用户,控制数据库的访问权限 ##### 5.3.1 DDL语句 SQL数据类型 - 基本数据类型 ![img_3.png](img/img_3.png) - 字符串数据类型 ![img_4.png](img/img_4.png) - 日期类型 ![img_5.png](img/img_5.png) | 命令 |用处| |-----------------------------------------------------------------------|---| | SHOW DATABASES; |查询所有数据库| | CREATE DATABASE[IF NOT EXIST] 数据库名[DEFAULT CHARSET字符集][COLLATE 排序规则]; |创建数据库| | DROP DATABASE [IF EXIST] 数据库名; |删除数据库| | SELECT DATABASE(); |查询当前数据库| | USE 数据库名; |切换数据库| | SHOW TABLES; |查询所有表| | DESC 表名; |查询表结构| | ![img_2.png](img/img_2.png) |创建数据表操作| | SHOW CREATE TABLE; |展示数据表的所有内容| | ALERT TABLE 表名 ADD 字段名 类型(长度) [comment注释]; |向已有数据表中添加字段| | ALERT TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度)[comment 注释][约束]; |修改表中已有字段内容| | ALERT TABLE 表名 DROP 字段名; |删除字段| | ALERT TABLE 表名 RENAME TO 新表名; |修改表名| ##### 5.3.2 DML增删改语言 对数据库中的数据记录进行增删改操作 | 命令 |用处| |-----------------------------------------------------------|---| | INSERT INTO 表名(字段一、字段二,....) VALUES(值一、值二),(值一、值二),....); |批量添加数据| | UPDATE 表名 SET 字段一=值一,字段二=值二,.....[WHERE 条件]; |修改表| | DELETE FROM 表名 [WHERE 条件]; |删除语句| ##### 5.3.3 DQL查询语句 用于查询数据库中表的记录,注意尽量不要在工作的时候使用*,不直观 ![img_6.png](img/img_6.png) DQL聚合函数 ![img_7.png](img/img_7.png) ![img_8.png](img/img_8.png) 查询总览 ![img_9.png](img/img_9.png) 例题: ![img_10.png](img/img_10.png) #### 5.4 字符串函数 ![img.png](img/img_16.png) #### 5.5 数值函数 ![img_1.png](img/img_17.png) #### 5.6 日期函数 ![img_2.png](img/img_18.png) #### 5.7 流程控制函数 ![img_3.png](img/img_19.png) 案例: ![img_4.png](img/img_20.png) #### 5.8 可视化工具 在Navicat中点击设计表可以看表中数据的类型 !!!SQL注入攻击:在mysql中的判断语句只要有一个是真就算真,所以容易被别人改代码改成永真语句而使密码检查失效。 #### 5.9 动态查询语句 创建PreparedStatement -> 设置参数 -> 执行语句 #### 5.10 数据库连接池 数据库连接池的作用就是为了提高数据库的访问效率,减少数据库的访问时间,提高程序的性能。 原本的数据库存在的问题是: 1. 网络IO较多 2. 数据库负载较大 3. 响应时间较长 4. 应用频繁创建和关闭连接,导致临时对象较多,占用内存较大 数据库连接池: 1.每次连接复用之前创建的链接,直接执行sql语句 数据库操作总结: 1. 指定数据库连接相关信息 2. 建立数据库连接 3. 创建SQL语句Statemment对象 4. 执行数据库操作语句 ### 第六章、Java多线程编程 ##### 6.1.1 线程状态与生命周期 在Java中,线程的状态包括 1. 新建(NEW) 2. 就绪(RUNNABLE) 3. 阻塞(BLOCKED) 4. 等待(WAITING) 5. 定时等待(TIMED_WAITING) 6. 终止(TERMINATED) ![img_2.png](IOStream/img_22.png) ##### 6.1.2 run方法和start方法的区别 run方法的线程是按照顺序依次执行,start方法就是直接开始 #### 6.2 多线程实现形式 1. 继承Thread类,重写run()方法 2. 实现Runnable接口,实现run()方法 3. 通过Callable接口创建线程 #### 6.3 线程的基本方法 ##### 6.3.1 线程的优先级 线程的优先级分为1-10级,其中1级最低,10级最高,默认是5级。 通过getPriority()方法查看以及获取线程的优先级,通过setPriority()方法设置线程的优先级。 ##### 6.3.2 线程的休眠 线程的休眠通过Thread.sleep()方法实现,不建议用对象名来实现休眠,例如在主线程中执行t1.sleep(1000)时真正sleep的是主线程,而非t1对象,其中参数是休眠的时间,单位是毫秒。 ##### 6.3.3 线程的中断 线程的中断通过Thread.interrupt()方法实现,其中参数是休眠的时间,单位是毫秒。 设置join()方法的参数,如果参数是0,那么就是永远等待,直到该线程执行完毕,如果参数是1000,那么就是等待1000毫秒,如果该线程在1000毫秒内执行完毕,那么就不用等待了。只有等待当前线程执行完成之后才能继续向下。 ##### 6.3.4 线程的终止 线程的终止通过Thread.stop()方法实现,其中参数是休眠的时间,单位是毫秒。 #### 6.4 线程的同步机制 ##### 6.4.1 几个重要概念 1. 并发:在同一时间内有多个线程处于“就绪”状态,但是任意时间点只有一个线程在工作。 2. 同步:统一配合共同完成任务,线程在执行某个功能调用的时候没得到返回结果就一直等待。 3. 异步:不用等待方法的返回结果,直接执行下一条语句。 4. 临界资源:多个线程同时访问的资源,比如说共享内存区域。 5. 临界区:访问临界资源的代码块。 6. 对象锁:每个对象都有一个锁,当线程访问某个对象的临界资源的时候,需要先获取该对象的锁,如果获取不到就会进入阻塞状态。 7. 原子操作:不可分割的操作,要么全部执行,要么全部不执行其顺序不能改变。 ##### 6.4.2 线程同步的实现 1. 同步方法(粗粒度锁) 给方法增加synchoronized关键字,这样就可以保证同一时间只有一个线程访问该方法。 public synchronized void method() { // 临界区 } 2. 同步代码块(细粒度锁) synchronized(对象) { // 临界区 } ##### 6.4.3 死锁 死锁的产生是因为两个线程都在等待对方释放锁,从而导致两个线程都无法继续执行下去。 ##### 6.4.4 volatile关键字 volatile关键字的作用是保证变量的可见性,当一个线程修改了某个变量的值,其他线程可以立即看到修改后的值,每次读取数据直接从主内存读取而非从缓存读取。 #### 6.5 线程间通信 ##### 6.5.1 等待/通知机制 等待/通知机制是指一个线程A调用了对象O的wait()方法进入等待状态, 而另一个线程B调用了对象O的notify()或者notifyAll()方法 线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。 ##### 6.5.2生产消费者模型 模型描述的就是两个共享缓存区域的线程, “生产者”负责向缓存中写入数据,但是当缓存满的时候就不再向其中写入数据; “消费者”负责从缓存中提取数据,但是当缓存中没有数据的时候就不再想向缓存中拿数据。 模型的设计: 1. 产品类 2. 缓冲区类 3. 生产者类 4. 消费者类 5. 测试类 ### 第七章、Java网络编程 #### 7.1 Java网络TCP编程的顺序: 1. 创建服务器端Socket,绑定端口号 2. 创建客户端Socket,指定服务器地址和端口号 3. 通过输入输出流进行数据的传输 5. 关闭ServerSocket 6. 关闭客户端Socket 7. 关闭服务器端Socket 9. 关闭客户端输入输出流 10. 关闭服务器端输入输出流 #### 7.2 Java网络UDP编程的顺序: 1. 创建服务器端DatagramSocket,指定端口号 2. 创建客户端DatagramSocket,指定服务器地址和端口号 3. 通过输入输出流进行数据的传输 4. 关闭客户端DatagramSocket 5. 关闭服务器端DatagramSocket #### 7.3 Socket编程 Socket编程是指通过Socket在两台计算机之间进行通信,其中一台为客户端,另一台为服务器端。 Socket编程分为TCP编程和UDP编程,其中TCP编程是面向连接的,UDP编程是面向无连接的。 ##### 7.3.1 Socket类和ServerSocket类 Socket类是Java中用于实现客户端的类,ServerSocket类是Java中用于实现服务器端的类。 在连接成功的时候,服务器端会创建一个Socket对象,而客户端也会创建一个Socket对象,这两个对象会相互连接,从而实现数据的传输,换句话说,当连接建立的时候客户端和服务器端没有差别