【15】Head First Java 学习笔记

HeadFirst Java

本人有C语言基础,通过阅读Java廖雪峰网站,简单速成了java,但对其中一些入门概念有所疏漏,阅读本书以弥补。

第一章 Java入门
第二章 面向对象
第三章 变量
第四章 方法操作实例变量
第五章 程序实战
第六章 Java函数库
第七章 继承与多态
第八章 深入多态
第九章 构造器与垃圾收集器
第十章 数字与静态
第十一章 异常处理
第十二章 GUI(内部类)
第十三章 Swing
第十四章 保存对象
第十五章 网络与线程


前言

终于来到一个超大头章节,网络与线程,后端开发的重要章节!这是让我们的程序连接到互联网世界的第一步!这一章以实现一个实时聊天程序为例子,介绍相关的内容~
在这里插入图片描述

连接、传送、接受

客户端的工作需要这三件事
1.与服务器建立连接
2.传送信息到服务器
3.从服务器接受信息

这之中涉及计算机网络的底层原理,但java.net包帮我们解决了,但还是应该深入去研究计算机网络相关知识。

建立Socket连接

Socket(java.net.Socket):是代表两个机器之间网络连接的对象
创建Socket连接需要知道机器在哪里,用哪个端口收发数据

Socket chatSocket = new Socket("196.164.1.103",5000);

在这里插入图片描述

TCP端口

网页服务器(HTTP)的端口号是80
TCP端口:16位宽的帮助客户端识别服务器特定服务程序的标志

不同程序不可共享一个端口
在这里插入图片描述
在这里插入图片描述

BufferedReader从Socket上读取数据

使用串流,Java的大部分I/O不在乎链接串流的上游
在这里插入图片描述

用PrintWriter写数据到Socket

相比读取,没有用缓冲区,原文说是每次都写入一个String,PrintWriter更标准
在这里插入图片描述

编写简单的服务器

需要一对Socket,一个等待用户请求(当用户创建Socket)的ServerSocket,一个与用户通信的Socket

对于服务器来说,这里1,3步的Socket是指一对Socket;第2步属于客户端做的事情
在这里插入图片描述

public void go() {try {ServerSocket serverSock = new ServerSocket(4242);while () {Socket sock = serverSock.accept();//停下来直到接收客户端请求//服务器创建出与客户端Socket通信的Socket,进行数据传送/*具体服务代码*/}}catch ()
}

具体代码 P486-

编写聊天客户端程序
第一版:可发送

客户端建立Socket连接到服务器,PrintWriter流获取Socket输出流
第二版:可发送和可接收
从服务器获得信息——与服务器Socket连接,BufferReader获取输入流
何时从服务器获得?
1.间隔查询
2.用户送出信息时,顺便读取信息
3.信息送到服务器上时读取

这里选择第三种方法,程序如何写呢?照前文提到的accept(),需要有个循环等待服务器信息,但GUI启动之后,只有事件触发才会有程序运转,循环应该放在哪里?

显然,我们这里需要同时执行两件事的程序,一个负责用户与GUI的交互,一个用于持续读取服务器的数据。这意味着我们需要新的线程与执行空间。

但现实我们并没有多个处理器CPU,Java的新线程并不会让OS多开一个进程,只是感觉像。这是一种用户态的多线程。具体的细节得学习操作系统,这里不多讲解。

线程与Thread

线程独立,对应独立的执行空间
Thread是Java中线程的类
在这里插入图片描述

多个执行空间?

真正的多线程(多空间)是多处理器并行执行多件事情。
实际:Java只是在底层OS上的执行的进程(即非并行),Java的线程实现模拟的并行(不同模拟空间的来回快速切换)

轮到Java进程时,JVM执行什么?——目前栈空间的最上层
在这里插入图片描述

如何启动新线程

Runnable job = new MyRunnable();//新建工作,runnable是接口
Thread thread = new Thread(job);//给工人安排工作,传入runnable(的run方法)
thread.start();//启动,执行工作(新空间第一个方法)

Thread是工人,Runnable是他的工作
Thread对象不可复用,线程的run()方法执行后,线程死亡。Thread对象还在堆上,一般方法可调用。

Runnable接口只有一个方法void run();
回忆:Runnable,为什么要作为接口?——便于多态,一种合约,不同的任务有不同实现方式的run()方法
不使用Runnable,用Thread子类实现run方法?——可以,但不够面向对象。从目的角度,理解为有特殊的工人,只执行特殊的任务。

线程的状态

新建——》可执行——》执行中

新建Thread对象
thread.start
JVM调度机制决定何时进入执行中状态
在这里插入图片描述

一、可执行与执行中交替

二、暂时不可执行(阻塞)

某些特殊原因,调转机制将进程 变为不可执行
在这里插入图片描述

线程调度器

调度器决定线程何时被执行,何时等待被执行,何时去阻塞。但它的机制是模糊的,没有API可以控制调度,就算同一台机器,其结果都是不可预测的。

经典的错误:在单一机器测试多线程程序,且认为其他机器的调度器有相同行为

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

图2第三部分,新建线程是被搁置的,这里写错了。

使用sleep()

让程序更好预测,强制当前进程进入一定时间阻塞。

可让所有线程有机会运行
会抛出InterruptException异常,需要try/catch块
在这里插入图片描述

多线程以及并发性问题

两个线程存取同一对象的数据,即两个执行空间对堆上同一对象执行getter,setter。这会引发严重的问题(如数据损毁)

关于数据的损毁,原书中举了一个有趣的例子,一对夫妻有公共资产,取钱,约定会先查询余额。丈夫查询后进入了睡眠,妻子在丈夫睡眠途中查询取钱。丈夫醒来不再查询,认为余额充足而取钱。最后导致直接负债。。。
相关代码P507,分析后的结论是:妻子或丈夫应该学会在另一方取钱前不进行查询操作,而这需要的是一个锁
在这里插入图片描述

对象的锁与同步化

synchronized(同步化),对方法声明修饰,让其像原子一样

原子(atomic):古典说法,不可分割之意

每个对象都有锁,可假设配有虚拟钥匙随时待命。大部分时间对象都没有被锁上。
锁只在同步化的方法上起作用,线程只有取得对象的锁(的钥匙),才能进入同步化的方法

具体的过程:
线程 调用 同步化方法
线程尝试取得 对象的锁(的钥匙)
若取得,其他线程不可进入 该对象的 任何同步化方法
完成方法后,解锁并释放钥匙

说是对象的锁,但其实锁住的是存取对象实例变量的方法(不让线程并发冲突)

经典并发问题:丢失更新问题
多个线程对余额进行+1操作

public class test implements Runnable {int balance;public void run() {inc();}public void inc() {//这里进行同步化修饰即可解决问题int i = balance;balance = i+1;}
}

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

同步化的代价

JVM查询钥匙的性能损耗
强制线程排队
死锁

局部同步化:

public void go() {do();//this.do();synchronized(this) {//参数写入对象,表示需要取用该对象的锁,this即当前对象(执行该行为的实例)//else}
}
死锁

两个线程互相持有对方需要的钥匙
在这里插入图片描述

处理死锁
数据库的方法:超时释放 + 事务回滚复原
Java:无处理机制,自行合理设计,学习《Java Thread》

其他

静态的方法可否同步化呢?

可以的,对应静态变量的保护,类也有锁(与钥匙)。线程需要取得类的锁,才能进入同步化的静态方法。

线程优先级

对调度器有一定影响,但依旧并不能确保准确性

为什么不把getter与setter同步化?

可以,但我们为什么同步化?是为了查询余额与提款 这两个不可分割的动作进行原子化。仅仅对getter与setter同步化,依旧会出现负债问题。

Singleton模式(单例模式)

class Accum {private static Accum a = new Accum();//静态实例private Accum() {}//私有构造函数
}

小结

本章很长!耐心看下来,很有收获,该书总能从为什么触发,一步一步引导你的思考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/831033.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基于微信小程序+uniapp的校园失物招领小程序(V3.0)

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

微软如何打造数字零售力航母系列科普06 - 如何使用微软的Copilot人工智能

如何使用微软的Copilot人工智能? Copilot和ChatGPT有很多相似之处,但微软的聊天机器人本身就有一定的优势。以下是如何对其进行旋转,并查看其最引人注目的功能。 ​​​​​​​ (资料来源:Lance Whitney/微软&…

NLP 笔记:TF-IDF

TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)是一种用于信息检索和文本挖掘的统计方法,用来评估一个词在一组文档中的重要性。TF-IDF的基本思想是,如果某个词在一篇文档中出现频率高&#xff0…

使用c++类模板和迭代器进行List模拟实现

List 一、创建节点结构二、创建迭代器类1、类的结构2、一系列的运算符重载 三、创建list1、细节把握2、迭代器函数3、构造函数和析构函数4、增删查改的成员函数 一、创建节点结构 template <class T>//节点结构 struct ListNode {ListNode<T>* _next;ListNode<…

Springboot+vue+小程序+基于微信小程序的在线学习平台

一、项目介绍    基于Spring BootVue小程序的在线学习平台从实际情况出发&#xff0c;结合当前年轻人的学习环境喜好来开发。基于Spring BootVue小程序的在线学习平台在语言上使用Java语言进行开发&#xff0c;在数据库存储方面使用的MySQL数据库&#xff0c;开发工具是IDEA。…

APScheduler定时器使用:django中使用apscheduler,使用mysql做存储后端

一、基本环境 python版本&#xff1a;3.8.5 APScheduler3.10.4 Django3.2.7 djangorestframework3.15.1 SQLAlchemy2.0.29 PyMySQL1.1.0二、django基本设置 2.1、新增一个app 该app用来写apscheduler相关的代码 python manage.py startapp gs_scheduler 2.2、修改配置文件s…

Ollamallama

Olllama 直接下载ollama程序&#xff0c;安装后可在cmd里直接运行大模型&#xff1b; llama 3 meta 开源的最新llama大模型&#xff1b; 下载运行 1 ollama ollama run llama3 2 github 下载仓库&#xff0c;需要linux环境&#xff0c;windows可使用wsl&#xff1b; 接…

C++浮点数format时的舍入问题

C浮点数format时的舍入问题 首先有这样一段代码&#xff1a; #include <iostream> #include <stdio.h> using namespace std;int main() {cout << " main begin : " << endl;printf("%.0f \r\n", 1.5);printf("%.0f \r\n&…

吴恩达2022机器学习专项课程(一)8.2 解决过拟合

目录 解决过拟合&#xff08;一&#xff09;&#xff1a;增加数据解决过拟合&#xff08;二&#xff09;&#xff1a;减少特征特征选择缺点 解决过拟合&#xff08;三&#xff09;&#xff1a;正则化总结 解决过拟合&#xff08;一&#xff09;&#xff1a;增加数据 收集更多训…

【c++】模板编程解密:C++中的特化、实例化和分离编译

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来学习模版的进阶部分 目录 1.非类型模版参数按需实例化 2.模版的特化函数模版特化函数模版的特化类模版全特化偏特化 3.分离编译模版分离编译 1.非类…

综合性练习(后端代码练习4)——图书管理系统

目录 一、准备工作 二、约定前后端交互接口 1、需求分析 2、接口定义 &#xff08;1&#xff09;登录接口 &#xff08;2&#xff09;图书列表接口 三、服务器代码 &#xff08;1&#xff09;创建一个UserController类&#xff0c;实现登录验证接口 &#xff…

网络应用层之(6)L2TP协议详解

网络应用层之(6)L2TP协议 Author: Once Day Date: 2024年5月1日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

Apollo Dreamview+之播放离线数据包

前提条件 完成 Dreamview 插件安装&#xff0c;参见 Studio 插件安装 。 操作步骤 您可以通过包管理和源码两种方式快速体验离线数据包播放操作。其中进入 docker 环境和启动 dreamview 的命令有所区别&#xff0c;请您按照命令进行操作。 步骤一&#xff1a;启动并打开 Dr…

C++学习第十四课:运算符类型与运算符重载

C学习第十四课&#xff1a;运算符类型与运算符重载 在C中&#xff0c;运算符重载是一种使得自定义类型&#xff08;如类对象&#xff09;能够使用C内建运算符的能力。运算符重载允许程序员定义运算符对用户定义类型的特殊行为&#xff0c;这增加了程序的可读性和自然表达能力。…

PaLmTac嵌入软体手手掌的视触觉传感器

触觉是感知和操作之间的桥梁。触觉信息对于手部行为反馈和规划具有重要意义。软体手的柔性特性在人机交互、生物医学设备和假肢等方面具有潜在应用的优势。本文提出了一种名为 PaLmTac的嵌入软体手手掌的视触觉传感器&#xff08;vision-based tactile sensor, VBTS&#xff09…

LeetCode 198—— 打家劫舍

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题使用动态规划求解&#xff0c;假设 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 代表不偷窃第 i i i 个房屋可以获得的最高金额&#xff0c;而 d p [ i ] [ 1 ] dp[i][1] dp[i][1] 代表偷窃第 i i i 个房屋可以获…

Bluetooth Profile 蓝牙协议栈总结

GAP-Generic Access Profile 控制设备广播和连接 GAP profile 的目的是描述&#xff1a; Profile rolesDiscoverability modes and proceduresConnection modes and proceduresSecurity modes and procedures 设备连接过程 LE中GAP有4种角色&#xff1a;BroadcasterObserv…

RTMP 直播推流 Demo(二)—— 音频推流与视频推流

音视频编解码系列目录&#xff1a; Android 音视频基础知识 Android 音视频播放器 Demo&#xff08;一&#xff09;—— 视频解码与渲染 Android 音视频播放器 Demo&#xff08;二&#xff09;—— 音频解码与音视频同步 RTMP 直播推流 Demo&#xff08;一&#xff09;—— 项目…

暴雨服务器引领信创算力新潮流

去年大模型的空前发展&#xff0c;人工智能也终于迎来了属于自己的“文艺复兴”&#xff0c;众多的模型相继发布&#xff0c;继而催生了整个行业对于智能算力需求的激增。 市场需求与技术驱动仿佛现实世界的左右脚&#xff0c;催动着世界文明的齿轮向前滚动。在全球经济角逐日…

力扣:61. 旋转链表(Java,双指针)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码描述&#xff1a; 题目描述&#xff1a; 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 输入&#xff1a; head [1,2,3,4,5], k 2 输出&#xff1a; [4,5,1,…