Java基础复习-下-多线程-网络编程-反射
多线程






实现方式
继承Thread

实现Runnable接口

实现Callable接口


成员方法-Thread




优先级


守护线程

举例:
线程1是非守护线程,线程2是守护线程。
当非守护线程执行结束时,线程2也就没必要存在了,系统会告诉线程2,你也要结束了。此时不管线程2是否执行完毕,都会停止当前的进度。但是,并不是线程1一停止,线程2立马结束,系统告诉线程2 让线程2结束的这一段时间,线程2还会执行。

礼让(出让)线程
当执行到Thread.yield()时,该线程会把cpu控制权交出去,然后重新抢夺cpu。当然,这个线程也可能会再次抢到cpu。

插入线程

线程的生命周期

jdk5.0以后的生命周期发生了变化。
线程安全问题
同步代码块
使用同步代码块将需要顺序执行的地方锁起来。


同步方法


用方法以继承Thread使用同步代码块,自己指定锁对象
用后面的实现Runnable接口的,可以使用同步方法,因为锁对象默认是this。也就是左边的mr
Lock锁


死锁
线程1拿着A锁等B锁
线程2拿着B锁等A锁
两个线程都在等对方释放锁。互相等待。

等待唤醒机制(生产者和消费者)


Desk:
public class Desk {
// 桌子,控制生产者和消费者的执行
// 桌子上是否有食物,0没有食物,1有食物public static int foodFlag = 0;// 消费者总共可以吃几次食物public static int consumerCount = 10;// 锁对象public static Object lock = new Object();
}Consumer:
public class Consumer extends Thread{@Overridepublic void run() {while (true){
// 锁监视器使用在Desk中创建的锁对象,为了后续生产者和消费者等待或唤醒synchronized (Desk.lock){if (Desk.consumerCount == 0){break;}else {
// 判断桌子上是否有食物if(Desk.foodFlag == 0){
// 没有食物,让绑定Desk.lock的线程进行等待try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {
// 有食物Desk.consumerCount--;System.out.println("消费者开始吃食物了,还可以吃 ---> " + Desk.consumerCount + " --- 份食物");
// 将桌子设置成没有食物的状态Desk.foodFlag = 0;
// 唤醒绑定了Desk.lock这把锁的所有生产者Desk.lock.notifyAll();}}}}}
}Producer:
public class Producer extends Thread{@Overridepublic void run() {while (true){synchronized (Desk.lock){
// 判断消费者是否还能吃食物if (Desk.consumerCount == 0){break;}else {
// 首先判断桌子上是否有食物if (Desk.foodFlag == 1){
// 桌子上已经有食物了try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {
// 桌子上没有食物System.out.println("生产者开始生产食物了,当前生产第 " + Desk.consumerCount + " 份食物");
// 将桌子设置成有食物的状态Desk.foodFlag = 1;
// 唤醒Desk.lock这个锁监视器上绑定的其他等待的线程Desk.lock.notifyAll();}}}}}
}测试:
public class Test {public static void main(String[] args) {Producer producer = new Producer();Consumer consumer = new Consumer();producer.setName("生产者");consumer.setName("消费者");producer.start();consumer.start();}
}测试结果:

使用阻塞队列来实现消费者和生产者的消费等待机制:

队列:


这里的queue的put方法和take方法不需要加锁,因为他们的底层都用了lock锁,我们无需再次加锁

这样打印出来的结果可能会出现连续的问题。这不是代码问题,因为我们把打印的语句放到了锁的外面。因为他的底层加锁了,但我们没法在底层源码中加锁。
多线程的6种状态
Java中没有定义运行这种状态,因为线程抢占到cpu后,程序就交给操作系统去处理了,jvm就不管了,所以,jdk没有定义运行状态,这里为了方便理解,写了运行状态。


线程栈:

例题:



测试类:

线程池


代码实现

创建没有上线的线程池(实际上是有上限的,int的最大数,电脑会先扛不住)

有上限的创建线程池

线程池的参数:


当核心线程全在处理任务,阻塞队列也排满了,临时线程也全部都在工作--线程池满负荷工作,那么再来其他任务,就会触发拒绝策略

拒绝策略:


public static void main(String[] args) {ThreadPoolExecutor pools = new ThreadPoolExecutor(3,6,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),// new LinkedBlockingQueue<>()new ThreadPoolExecutor.AbortPolicy());}线程池参数设置问题:


后续资料可以看黑马Java课程下部的:juc额外扩展资料
网络编程




概念:
IP


IPv4

Ipv6






端口号

网络通信协议



InetAddress

UDP通信
UDP发送数据


UDP接收数据



通信案例

发送端:

接收端:

UDP的通信方式:


代码实现:
组播
发送端:

接收端:

广播
就是把地址改成255.255.255.255即可

TCP通信方式


代码实现:
发送端:

接收端:

这种字节流只能传输英文,传输中文会导致乱码问题
解决乱码问题:
在接收端,使用转换流,将字节流转成字符流,后续也可以继续使用缓存字符流来包装提升读取速度。

代码:
public class TcpTestWriter {
// 发送端public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1",65535);BufferedWriter bos = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bos.write("你好你好,Java");bos.close();socket.close();}
}
public class TcpTestReader {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(65535);Socket socket = ss.accept();// 等待建立连接BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int len;char[] c1 = new char[1024];while ((len = br.read(c1)) != -1){System.out.println(new String(c1,0,len));}br.close();socket.close();}
}
三次握手、四次挥手


双向读写数据


大作业:聊天室
源代码:
客户端:
public class Client {
// 用户端口
static ThreadPoolExecutor pool;static {pool = new ThreadPoolExecutor(3,6,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1",65535);
// System.out.println("连接服务端成功");Scanner scanner = new Scanner(System.in);System.out.println("---欢迎来到星河网络聊天室---");while (true){System.out.println("1、登录!");System.out.println("2、注册!");System.out.println("请输入要执行的操作:");String choose = scanner.nextLine();switch (choose){case "1" -> login(socket);case "2" -> System.out.println("注册");}}}private static void login(Socket socket) throws IOException {Scanner scanner = new Scanner(System.in);while (true){System.out.println("请输入用户名");String username = scanner.nextLine();System.out.println("请输入密码");String password = scanner.nextLine();StringBuffer sb = new StringBuffer();sb.append("username=").append(username).append("&password=").append(password);sendMessage2Server(socket,"login");sendMessage2Server(socket,sb.toString());BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String str = br.readLine(); // 这里返回登录状态码:1、登录成功 2、密码错误 3、用户名不存在System.out.println(str);switch (str){case "1" -> {System.out.println("登录成功");
// new Thread(new Client2Runnable(socket)).start();pool.submit(new Client2Runnable(socket));chat2Server(socket);}case "2" -> System.out.println("密码错误");case "3" -> System.out.println("用户名不存在");}}}private static void chat2Server(Socket socket) throws IOException {Scanner scanner = new Scanner(System.in);while (true){System.out.println("请输入要发送的内容:");String message = scanner.nextLine();sendMessage2Server(socket,message);}}public static void sendMessage2Server(Socket socket,String msg) throws IOException {BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(msg);bw.newLine();bw.flush();// 由于使用了缓存输出字符流,所以需要刷新缓冲区}
}class Client2Runnable implements Runnable{Socket socket;public Client2Runnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));while (true){String message = br.readLine();System.out.println(message);}} catch (IOException e) {throw new RuntimeException(e);}}
}服务端:
public class Server {// 服务端
// 定义一个全局变量,存储每个连接到服务端的socket,
// 由于要使用多线程,为了线程安全,这里不建议使用ArrayList
// static ArrayList<Socket> list = new ArrayList<>();static CopyOnWriteArrayList<Socket> list = new CopyOnWriteArrayList<>();static ThreadPoolExecutor pool;static {pool = new ThreadPoolExecutor(3,6,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(65535);Properties prop = new Properties();FileInputStream fis = new FileInputStream("F:\\Java\\code\\testcode\\study-javase\\userinfo\\user.txt");prop.load(fis);fis.close();
// System.out.println(prop);while (true) {Socket socket = ss.accept();// 监听65535端口,等待连接
// 有客户端连接后,拿到这个客户端socketSystem.out.println("有客户端连接成功"); // 每次有一个客户端连接,就开启一条线程去执行接受消息和群发
// new Thread(new ServerRunnable(socket, prop)).start();pool.submit(new ServerRunnable(socket, prop));}}
}class ServerRunnable implements Runnable {Socket socket;Properties prop;public ServerRunnable(Socket socket, Properties prop) {this.socket = socket;this.prop = prop;}@Overridepublic void run() {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));while (true) {String pd = br.readLine();
// if (pd == null) {
// // 客户端断开连接
// System.out.println("客户端断开连接");
// break;
// }System.out.println(pd);if ("login".equals(pd)) {login(br);}}} catch (IOException e) {throw new RuntimeException(e);}}private void login(BufferedReader br) throws IOException {String str = br.readLine();System.out.println(str);String[] strArr = str.split("&");String usernameInput = strArr[0].split("=")[1];String passwordInput = strArr[1].split("=")[1];
// UserInfo user = UserInfo.builder().username(usernameInput).password(passwordInput).build();if (prop.containsKey(usernameInput)) {if (passwordInput.equals(prop.get(usernameInput))) {
// 登录成功,开始聊天System.out.println("登录成功");sendMessage2Client("1");Server.list.add(socket);
// 开始聊天getAndSendMsg2AllClient(usernameInput);} else {System.out.println("密码错误");sendMessage2Client("2");}} else {System.out.println("用户不存在");sendMessage2Client("3");}}private void getAndSendMsg2AllClient(String usernameInput) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));while (true) {String msg = br.readLine();System.out.println(usernameInput + "说 -> " + msg);Server.list.forEach(s -> {try {sendMessage2Client(s, usernameInput + "说 -> " + msg);} catch (IOException e) {throw new RuntimeException(e);}});}}private void sendMessage2Client(String msg) throws IOException {/*这种写法需要手动拼接 \n 换行符号OutputStream outputStream = socket.getOutputStream();outputStream.write((msg + "\n").getBytes());outputStream.flush();*/BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(msg);bw.newLine();bw.flush();}private void sendMessage2Client(Socket s, String msg) throws IOException {
// OutputStream outputStream = socket.getOutputStream();BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));bw.write(msg);bw.newLine();bw.flush();}
}
/*
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class UserInfo{private String username;private String password;
}
*/在老师的基础上改了部分内容
效果:

反射


获取Class的三种方式


反射获取构造方法


反射获取成员变量


反射获取成员方法



案例
将传过来的对象里面的值存入本地文件


动态代理


代码实现




