Java10
Java10
- (一)、配置文件
- (二)、多线程
- 2.1 并发和并行
- 2.2 多线程的实现方式
- 2.3 常见成员方法
- 2.3.1 线程的优先级
- 2.3.2 守护线程(备胎线程)
- 2.3.3 礼让线程和插入线程
- 2.4 线程生命周期
- 2.5 线程安全问题
- 2.6 锁
- 2.6.1 死锁
- 2.7 等待唤醒机制
- 2.7.1 阻塞队列实现等待唤醒机制
- 2.8 多线程的6种状态
- 2.9 综合练习
- 2.9.1 送礼物
- 2.9.2 抢红包
- 2.9.3抽奖1
- 2.9.4 抽奖2 (多线程的统计)
- 2.9.5 抽奖3(多线程的比较)
- 2.10 线程池
- 2.10.1 自定义线程池
- (三)、网络编程
- 3.1 网络编程三要素
- 3.1.1 IP
- 3.1.2 InetAddress类
- 3.1.3 端口号
- 3.1.4 协议
- 3.1.4.1 UDP协议
- 3.1.4.1 TCP协议
- 3.2 综合练习
- 3.2.1 多发多收
- 3.2.2 接收和反馈
- 3.2.3 上传文件
- 3.2.4 上传文件(多线程版)
- 3.2.5 BS架构
- 3.2.6 聊天室
- (四)、反射
- 4.1 获取class对象三种方法
- 4.2 反射获取
- 4.3 练习
- (五)、动态代理
(一)、配置文件
好处:
1.可以把软件的设置永久化存储
2.如果我们要修改参数,不需要改动代码,直接修改配置文件就行
properties配置文件:
后缀名就是properties
文件中数据都是按照键值对存储
可以往Properties添加任意类型数据,但是一般只添加string类型数据
特有方法:store和load
load(加载):把本地文件数据加载进程序中
store(保存):把数据写进本地文件
(二)、多线程
多线程可以让程序同时做多件事情,提高运行效率
线程:操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位(应用软件中相互独立,可以同时运行的功能)
进程:是程序的基本执行实体 (一个软件运行之后就是一个进程)
2.1 并发和并行
并发:同一时刻,多个指令在单个cpu上交替执行
并行:同一时刻,多个指令在多个cpu上同时执行
2.2 多线程的实现方式
1.继承Thread类的方式进行实现
测试类:
package dxc;public class d1 {public static void main(String[] args) {/** 多线程的第一种启动方式:* 1.定义一个类继承Thread* 2.重写run方法* 3.创建子类的对象,并启动线程** */MyThread t1=new MyThread();MyThread t2=new MyThread();t1.setName("线程1");t2.setName("线程2");//开启线程t1.start();t2.start();//交替运行}
}
MyThread:
package dxc;public class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i <100 ; i++) {System.out.println(getName()+"HelloWorld");}}
}
2.实现Runnable接口的方式进行实现
测试类:
package dxc;public class d2 {public static void main(String[] args) {/** 1.自己定义一个类实现Runnable接口* 2.重写里面的run方法* 3.创建自己的类的对象* 4.创建一个Thread类的对象,并开启线程* *///创建MyRun对象,表示多线程要执行的任务MyRun mr=new MyRun();//创建线程对象Thread t1=new Thread(mr);//将要执行的任务放进去Thread t2=new Thread(mr);//给线程设置名字t1.setName("线程1");t2.setName("线程2");t1.start();t2.start();//交替执行}
}
MyRun:
package dxc;public class MyRun implements Runnable{@Overridepublic void run() {//书写线程要执行的代码for (int i = 0; i < 100; i++) {//获取到当前线程的对象Thread t = Thread.currentThread();System.out.println(t.getName()+"HelloWorld");}}
}
3.利用Callable接口和Future接口方式实现
测试类:
package dxc;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class d3 {public static void main(String[] args) throws ExecutionException, InterruptedException {/** 特点:可以获取多线程运行的结果** 1.创建一个类MyCallable实现Callable接口* 2.重写call(有返回值,表示多线程运行结果)* 3.创建MyCallable的对象(表示多线程要执行的任务)* 4.创建FutureTask对象(管理多线程运行的结果)* 5.创建Thread类的对象,并启动(表示线程)* */MyCallable mc=new MyCallable();FutureTask<Integer> ft=new FutureTask<>(mc);Thread t1=new Thread(ft);t1.start();Integer result = ft.get();System.out.println(result);}
}
MyCallable:
package dxc;import java.util.concurrent.Callable;public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum=0;for (int i = 0; i < 100; i++) {sum+=i;}return sum;}
}
三种实现方式优缺点:
2.3 常见成员方法
注:
如果不给线程设置名字,线程有默认名字
格式:Thread-x(x从0开始)
Thread构造方法可以传递一个字符串,直接设置线程名字
JVM虚拟机启动后,会自动启动多条线程,
其中一条线程叫main线程,作用是调用main方法,并执行里面的代码
sleep():哪条线程执行到这个方法,这条线程就会在这里停留对应的时间
方法的参数就是停留的时间,毫秒。时间到了后,线程会自动醒来,继续执行下面其他代码
2.3.1 线程的优先级
Java中线程是抢占式调度(随机)
默认线程优先级是5
优先级:1-10(1最小)
优先级高,只是抢占cpu概率大,先执行完的概率大,但并非100%抢占
2.3.2 守护线程(备胎线程)
当其他非守护线程执行完毕之后,守护线程也会陆续执行完毕
2.3.3 礼让线程和插入线程
礼让线程:出让cpu的执行权
用在run方法中,尽可能让执行结果均匀
插入线程:
package dxc;public class d5 {public static void main(String[] args) throws InterruptedException {MyThread t=new MyThread();t.setName("土豆");t.start();//表示把t这个线程插入到当前线程之前//t:土豆//当前线程:main线程t.join();//执行在main线程当中的for (int i = 0; i < 10; i++) {System.out.println("main线程"+i);}}
}
2.4 线程生命周期
sleep结束后,是不会立即执行下方代码的,要等抢到执行权
2.5 线程安全问题
线程执行有随机性。产生如数据越界,重复等等问题
同步代码块:
把操作共享数据的代码锁起来
格式:
锁对象可以是任意的,但是锁对象一定是唯一的
特点1:锁默认打开,有一个线程进去了,锁自动关上
特点2:当里面所有代码执行完毕,线程出来,锁自动打开
注:同步代码块不能写在循环的外面
锁对象可以使用当前类的字节码文件对象。类名.class
同步方法:把synchronized加在方法上,写在修饰符后面
特点:1.同步方法是锁住方法里面所有的代码
2.锁对象不能自己指定:非静态方法:this。静态方法:当前类的字节码文件对象
StringBuffer用于多线程安全中
需求:100个票,三个窗口卖票
package dxDemo;public class MyRunnable implements Runnable{int ticket=0;@Overridepublic void run() {//1.循环//2.同步代码块(同步方法)//3.判断共享数据是否到了末尾while (true){if (method()) break;}}private synchronized boolean method(){if (ticket==100){return true;}else {ticket++;System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");}return false;}
}
test:
package dxDemo;public class test {public static void main(String[] args) {MyRunnable mr=new MyRunnable();Thread t1=new Thread(mr);Thread t2=new Thread(mr);Thread t3=new Thread(mr);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}
2.6 锁
手动上锁和释放锁:
void lock():获得锁
void unlock():释放锁
卖票代码改成手动锁
package dxDemo;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyRunnable implements Runnable{static int ticket=0;static Lock lock=new ReentrantLock();@Overridepublic void run() {//1.循环//2.同步代码块(同步方法)//3.判断共享数据是否到了末尾while (true){lock.lock();try {if (ticket==100){break;}else {Thread.sleep(10);ticket++;System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");}} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();}}}}
2.6.1 死锁
是一种错误(一个线程拿a锁,一个拿b锁,都在等对方解锁)
不要让锁嵌套,容易造成死锁,使代码卡死
2.7 等待唤醒机制
生产者和消费者模式
生产者:生产数据
消费者:消费数据
常见方法:
需求:完成生产者和消费者等着唤醒机制的代码
实现线程轮流交替执行过程
厨师代码:
package dxcday2;public class Cook extends Thread{@Overridepublic void run() {/** 1.循环* 2.同步代码块* 3.判断共享数据是否到了末尾,到了* 4.没到,执行核心逻辑* */while (true){synchronized (Desk.lock){if (Desk.count==0){break;}else {//判断桌子有没有食物if(Desk.foodFlag==1){//有就等待try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {System.out.println("厨师做了一碗面条");//没有就制作,修改桌子状态Desk.foodFlag=1;//唤醒消费者开吃Desk.lock.notifyAll();}}}}}
}
食客代码:
package dxcday2;public class Fooddie extends Thread{/** 1.循环* 2.同步代码块* 3.判断共享数据是否到了末尾,到了* 4.没到,执行核心逻辑* */@Overridepublic void run() {while (true){synchronized (Desk.lock ){if (Desk.count==0){break;}else {//判断桌子上有没有面条//没有就等待if (Desk.foodFlag==0){try {Desk.lock.wait();//让当前线程跟锁绑定} catch (InterruptedException e) {throw new RuntimeException(e);}}else {Desk.count--;//总数-1,要先-1再打印//有就开吃System.out.println("食客在吃面条,还能吃"+Desk.count+"碗");//吃完要唤醒厨师,并且总数-1,修改桌子状态Desk.lock.notifyAll();//唤醒Desk.foodFlag=0;//修改桌子状态}}}}}
}
凳子代码:
package dxcday2;public class Desk {/** 控制生产者和消费者的执行* *///表示桌子上是否有面条,0是没有,1是有//如果有多线程,直接定义这个值就行public static int foodFlag=0;//总个数(能吃几碗面)public static int count=10;//锁对象public static Object lock=new Object();}
测试代码:
package dxcday2;public class dxc1 {public static void main(String[] args) {/** 需求:完成生产者和消费者等着唤醒机制的代码* 实现线程轮流交替执行过程* *///创建线程对象Cook c=new Cook();Fooddie fd=new Fooddie();c.setName("厨师");fd.setName("食客");c.start();fd.start();}}
2.7.1 阻塞队列实现等待唤醒机制
厨师put数据进管道
食客take数据
take方法和put方法底层都有锁,写代码时不需要加锁
实现了四个接口:
两个实现类:
ArrayBlockingQueue:底层是数组,有界
LinkedBlockingQueue:底层是链表,无界。但不是真正无界,界限是int的最大值
Cook代码:
package dxcday2_1;import java.util.concurrent.ArrayBlockingQueue;public class Cook extends Thread{ArrayBlockingQueue<String> queue;public Cook(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while (true){//不断添加面条进阻塞队列中try {queue.put("面条");System.out.println("厨师放了一碗面条进去");//打印语句在锁的外面,所以执行时看起来数据是乱的,实际上是正确的。没有影响到共享数据} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
Fooddie:
package dxcday2_1;import java.util.concurrent.ArrayBlockingQueue;public class Fooddie extends Thread {ArrayBlockingQueue<String> queue;public Fooddie(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while (true) {//不断从阻塞队列中获取面条try {String food = queue.take();System.out.println(food);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
Test:
package dxcday2_1;import java.util.concurrent.ArrayBlockingQueue;public class Test {public static void main(String[] args) {ArrayBlockingQueue<String> abq=new ArrayBlockingQueue<>(1);//创建线程把阻塞队列传递过去Cook c=new Cook(abq);Fooddie f=new Fooddie(abq);c.start();f.start();}
}
2.8 多线程的6种状态
实际上Java虚拟机中没有运行状态
2.9 综合练习
2.9.1 送礼物
线程1:
package dxczhlx;public class p2 extends Thread{@Overridepublic void run() {while (true){synchronized (lw.lock){if (lw.i<=10){break;}else {try {sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(getName()+"送出第"+lw.i+"份礼物");lw.i--;}}}}
}
线程2:
package dxczhlx;public class p1 extends Thread{@Overridepublic void run() {while (true){synchronized (lw.lock){if (lw.i<=10){break;}else {try {sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(getName()+"送出第"+lw.i+"份礼物");lw.i--;}}}}
}
控制类:
package dxczhlx;public class lw {public static int i=100;public static Object lock=new Object();
}
test:
package dxczhlx;public class test {public static void main(String[] args) {p1 p1=new p1();p2 p2=new p2();p1.setName("小程");p2.setName("小羊");p1.start();p2.start();}
}
2.9.2 抢红包
MyThread:精确数字使用BigDecimal
package lx2;import java.util.Random;public class MyThread extends Thread{//共享数据//100块,分3个包static double money=100;static int count=3;//最小的中奖金额static final double MIN=0.01;@Overridepublic void run() {synchronized (MyThread.class){if (count==0){//判断共享数据是否到了末尾,已经到了System.out.println(getName()+"没有抢到红包");}else {//没到//不能直接随机//定义一个变量,表示中奖金额double prize=0;if (count==1){//表示此时最后一个红包,无需随机,金额就是剩余金额prize=money;}else {//表示第一次和第二次Random r=new Random();//100-(3-1)*0.01 第一个红包最多99.98元double bounds=money-(count-1)*MIN;prize=r.nextDouble(bounds);//jdk17的方法if (prize<MIN){prize=MIN;//如果随机金额小于最小金额,强制变成最小金额}}//从money中去掉当前中奖金额money=money-prize;//红包个数-1count--;//打印本次红包信息System.out.println(getName()+"抢到了"+prize+"元");}}}
}
test:
package lx2;public class test {public static void main(String[] args) {MyThread t1=new MyThread();MyThread t2=new MyThread();MyThread t3=new MyThread();MyThread t4=new MyThread();MyThread t5=new MyThread();t1.setName("小1");t2.setName("小2");t3.setName("小3");t4.setName("小4");t5.setName("小5");t1.start();t2.start();t3.start();t4.start();t5.start();}
}
2.9.3抽奖1
可以将sleep方法写在锁的外面,使结果尽可能平均
MyThread:
package lx3;import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;public class MyThread extends Thread{//定义共享数据ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}@Overridepublic void run() {while (true){synchronized (MyThread.class){if (list.size()==0){break;}else {//继续抽奖Collections.shuffle(list);int prize = list.remove(0);System.out.println(getName()+"又产生了"+prize+"元大奖");}}}}}
Test:
package lx3;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {//创建奖池ArrayList<Integer> list=new ArrayList<>();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);MyThread t1=new MyThread(list);MyThread t2=new MyThread(list);t1.setName("抽奖箱1");t2.setName("抽奖箱2");t1.start();t2.start();}
}
2.9.4 抽奖2 (多线程的统计)
MyThread:
package lx4;import java.util.ArrayList;
import java.util.Collections;public class MyThread extends Thread{//定义共享数据ArrayList<Integer> list;//创建集合存储抽到的金额//线程一static ArrayList<Integer> list1=new ArrayList<>();//线程二static ArrayList<Integer> list2=new ArrayList<>();public MyThread(ArrayList<Integer> list) {this.list = list;}@Overridepublic void run() {while (true){synchronized (MyThread.class){if (list.size()==0){if ("抽奖箱1".equals(getName())){int result1=0;int max1=0;for (Integer num : list1) {result1+=num;if (num>max1){max1=num;}}System.out.println("抽奖箱1"+list1+","+"总金额为"+result1+","+"最大值为"+max1);}else {int result2=0;int max2=0;for (Integer num : list2) {result2+=num;if (num>max2){max2=num;}}System.out.println("抽奖箱2"+list2+","+"总金额为"+result2+","+"最大值为"+max2);}break;}else {//继续抽奖Collections.shuffle(list);int prize = list.remove(0);//System.out.println(getName()+"又产生了"+prize+"元大奖");if ("抽奖箱1".equals(getName())){list1.add(prize);}else {list2.add(prize);}}}}}}
Test:
package lx4;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {//创建奖池ArrayList<Integer> list=new ArrayList<>();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);MyThread t1=new MyThread(list);MyThread t2=new MyThread(list);t1.setName("抽奖箱1");t2.setName("抽奖箱2");t1.start();t2.start();}
}
改进:把存储金额的集合放在run方法中,不同线程会在自己的栈中创建集合
每一个线程都有一个栈
2.9.5 抽奖3(多线程的比较)
MyCallable:
package lx5;import lx4.MyThread;import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;public class MyCallable implements Callable<Integer> {//定义共享数据ArrayList<Integer> list;public MyCallable(ArrayList<Integer> list) {this.list = list;}@Overridepublic Integer call() throws Exception {ArrayList<Integer> boxlist=new ArrayList<>();while (true){synchronized (MyThread.class){if (list.size()==0){System.out.println(Thread.currentThread().getName()+boxlist);break;}else {//继续抽奖Collections.shuffle(list);int prize = list.remove(0);boxlist.add(prize);}}Thread.sleep(10);}//返回集合最大值if (boxlist.size()==0){return null;}else {return Collections.max(boxlist);}}
}
test:
package lx5;import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {ArrayList<Integer> list=new ArrayList<>();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);//创建多线程要运行的参数对象MyCallable mc=new MyCallable(list);//创建多线程运行结果管理者对象FutureTask<Integer> ft1=new FutureTask<>(mc);FutureTask<Integer> ft2=new FutureTask<>(mc);//创建线程Thread t1=new Thread(ft1);Thread t2=new Thread(ft2);t1.setName("抽奖箱1");t2.setName("抽奖箱2");t1.start();t2.start();Integer max1 = ft1.get();Integer max2 = ft2.get();if (max1>max2){System.out.println("抽奖箱1产生最大奖项,金额为"+max1);}else {System.out.println("抽奖箱2产生最大奖项,金额为"+max2);}}
}
2.10 线程池
用来存放线程的容器
主要核心原理:
1.创建一个池子,池子中是空的
2.提交任务 时,池子会创建新的线程对象,任务执行完毕,线程归还给池子。下次再提交任务时,不需要创建新的线程,复用已有线程
3.如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
Executors:线程池的工具类通过调用方法返回不同类型的线程池对象
submit():提交任务
shutdown:销毁线程池
2.10.1 自定义线程池
ThreadPoolExecutor
七个参数:
1.核心线程数量
2. 线程池中最大线程的数量(>=核心线程数量)
3. 空闲时间(值)
4. 空闲时间(单位)(用TimeUnit指定)
5. 阻塞队列
6. 创建线程的方式
7. 要执行的任务过多时的解决方案
临时线程是,核心线程都在使用且阻塞队列排满了,才会创建临时线程执行任务
先提交的任务不一定先执行
如果任务数>核心线程+临时线程+队伍长度,会触发任务拒绝策略
任务拒绝策略:是ThreadPoolExecutor的内部类
package zdydxc;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class z1 {public static void main(String[] args) {ThreadPoolExecutor pool=new ThreadPoolExecutor(3,//核心线程数量6,//最大线程数60,//空闲线程最大存活时间TimeUnit.SECONDS,//时间对象new ArrayBlockingQueue<>(3),//任务队列Executors.defaultThreadFactory(),//创建线程工厂new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略);}
}
最大并行数:cpu的最大线程数
线程池的大小如何定义?
CPU密集型运算(计算较多):最大并行数+1
I/O密集型运算(读取本地文件或数据库较多):
使用Thread dump工具测试CPU计算时间和等待时间
(三)、网络编程
在网络通信协议下,不同计算机上运行的程序,进行的数据传输
Java中,使用java.net包下的技术
常见软件架构:
B/S:浏览器/服务器
只需要一个浏览器,用户通过不同的网址。客户访问不同的服务器
优点:不需要开发客户端,只需要页面+服务端
用户不需要下载,打开浏览器就能使用
缺点:如果应用过大,用户体验差
C/S:客户端/服务器
在用户本地需要下载并安装客户端程序
在远程有一个服务端程序
优点:画面精美,用户体验好
缺点:需要开发客户端和服务端。用户下载和更新麻烦
3.1 网络编程三要素
ip:设备在网络中的地址,是唯一的标识
端口号 :应用程序在设备中唯一的标识
协议:数据在网络中传输的规则,常见协议有UDP、TCP、http、https、ftp
3.1.1 IP
上网设备在网络中的地址,是唯一的
常见分类:
IPv4:互联网通信协议第四版
采用32位地址长度,分成四组。总共42亿多ip,已经分配完毕
分类:
公网地址(万维网使用)和私有地址(局域网使用)
192.168.开头就是私有地址
特殊ip:127.0.0.1:回送地址也称本地回环地址,本机ip,永远只会寻找当前所在本机
CMD命令:ipconfig:查看本机IP地址。ping:检查网络是否连通
IPv6:互联网通信协议第六版
128位地址长度,分8组
最多2的128次方个ip
3.1.2 InetAddress类
package zdydxc;import java.net.InetAddress;
import java.net.UnknownHostException;public class z2 {public static void main(String[] args) throws UnknownHostException {InetAddress address= InetAddress.getByName("LAPTOP-B2IFU3U3");//可以传递主机名,也可以传递ipSystem.out.println(address);String name = address.getHostName();//获取主机名System.out.println(name);String ip = address.getHostAddress();//获取ipSystem.out.println(ip);}
}
3.1.3 端口号
由两个字节表示的整数,取值范围0-65535
其中0-1023用于一些知名的网络服务或应用
我们自己使用1024以上的就可以
注:一个端口号只能被一个应用程序使用
3.1.4 协议
UDP协议:用户数据报协议
面向无连接的通信协议
速度快,有大小限制一次最多发送64k,数据不安全,容易丢失数据
TCP协议:传输控制协议
面向有连接的通信协议
速度慢,没有大小限制,数据安全
3.1.4.1 UDP协议
发送数据:
1.创建发送端的DatagramSocket对象
2.数据打包(DatagramPacket)
3.发送数据
4.释放资源
package zdydxc;import java.io.IOException;
import java.net.*;public class z3 {public static void main(String[] args) throws IOException {//绑定端口 通过这个端口往外发送数据//空参:从所有可用端口中随机一个使用//有参:指定端口号进行绑定DatagramSocket ds=new DatagramSocket();//打包数据String str="你好";byte[] bytes = str.getBytes();InetAddress address=InetAddress.getByName("127.0.0.1");int port=10086;DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port); //发送数据ds.send(dp);//释放资源ds.close();}
}
接受数据:
1.创建DatagramSocket对象
2.接收打包好的数据
3.解析数据包
4.释放资源
package zdydxc;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class z3js {public static void main(String[] args) throws IOException {//创建对象//接受时必须绑定端口,并且绑定端口要和发送端口保持一致DatagramSocket ds=new DatagramSocket(10086);//接收数据包byte[] b1=new byte[1024];DatagramPacket dp=new DatagramPacket(b1,b1.length);//该方法是阻塞的//程序执行到这一步,会在这里死等//等发送端发送消息ds.receive(dp);//解析数据包byte[] data = dp.getData();int length = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到数据"+new String(data,0,length));System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口发送的");ds.close();}
}
练:
发送端:
package udplx;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class send {public static void main(String[] args) throws IOException {DatagramSocket ds=new DatagramSocket();Scanner sc=new Scanner(System.in);System.out.println("请输入要说的话:");while (true) {String str = sc.nextLine();if ("886".equals(str)){break;}byte[] bytes = str.getBytes();InetAddress address=InetAddress.getByName("127.0.0.1");int port=10086;//打包数据DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port);//发送ds.send(dp);}ds.close();}
}
接收端:
package udplx;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class receive {public static void main(String[] args) throws IOException {DatagramSocket ds=new DatagramSocket(10086);byte[] bytes=new byte[1024];DatagramPacket dp=new DatagramPacket(bytes,bytes.length);while (true) {ds.receive(dp);byte[] data = dp.getData();int length = dp.getLength();System.out.println(new String(data,0,length));}}
}
UDP三种通信方式:
单播:一对一
组播:给一组电脑发送数据
组播地址:224.0.0.0-239.255.255.255
其中224.0.0.0-224.0.0.255为预留组播地址
组播创建的是MulticastSocket对象,其他代码与单播差不多
接收端要将本机添加到组中
广播:给所有电脑发送数据
广播地址:255.255.255.255
广播代码与单播一样,ip改成广播地址就行
3.1.4.1 TCP协议
客户端:
1.创建客户端的Socket对象与指定服务端连接
2.获取输出流,写数据
3.释放资源
package tcp;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class client {public static void main(String[] args) throws IOException {//创建对象的同时会连接服务端//如果连接不上,代码会报错Socket socket=new Socket("127.0.0.1",10000);//获取输出流OutputStream os = socket.getOutputStream();//写出数据os.write("aaa".getBytes());//3.释放资源os.close();socket.close();}
}
服务端:
1.创建服务端的Socket对象(ServerSocket)
2.监听客户端连接,返回一个Socket对象
3.获取输入流,读数据,并把数据显示在控制台
4.释放资源
package tcp;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class server {public static void main(String[] args) throws IOException {//创建对象,保证与客户端端口一致ServerSocket ss=new ServerSocket(10000);//监听客户端的连接Socket socket = ss.accept();//从连接通道获取输入流InputStream is = socket.getInputStream();int b;while ((b=is.read()) !=-1){System.out.println((char) b);}socket.close();ss.close();}
}
中文乱码问题:将字节流转换字符流
package tcp;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class server {public static void main(String[] args) throws IOException {//创建对象,保证与客户端端口一致ServerSocket ss=new ServerSocket(10000);//监听客户端的连接Socket socket = ss.accept();//从连接通道获取输入流InputStream is = socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);int b;while ((b=isr.read()) !=-1){System.out.println((char) b);}socket.close();ss.close();}
}
三次握手和四次挥手协议
三次握手:保证连接的建立
四次挥手:确保连接断开,并且数据处理完毕
3.2 综合练习
3.2.1 多发多收
Client:
package lx1;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {//创建对象Socket socket=new Socket("127.0.0.1",8000);//输出数据Scanner sc=new Scanner(System.in);OutputStream os = socket.getOutputStream();while (true) {System.out.println("输入要发送的信息");String str = sc.nextLine();if ("886".equals(str)){break;}os.write(str.getBytes());}socket.close();}
}
server:
package lx1;import jdk.nashorn.internal.runtime.Scope;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {ServerSocket serverSocket=new ServerSocket(8000);Socket socket = serverSocket.accept();InputStream is = socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);int b;while ((b=isr.read()) !=-1){System.out.println((char) b);}socket.close();serverSocket.close();}
}
3.2.2 接收和反馈
Server:
package lx2;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//创建对象ServerSocket serverSocket=new ServerSocket(8001);//等待连接Socket socket = serverSocket.accept();InputStream is = socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);//读取数据//read方法需要有一个结束标记才会,结束读取//不然程序会一直停在这个循环当中,等待读取数据int b;while ((b=isr.read()) !=-1){System.out.println((char) b);}//回写数据String str="到底有多开心";OutputStream os = socket.getOutputStream();os.write(str.getBytes());socket.close();serverSocket.close();}
}
Client:
package lx2;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//创建对象Socket socket=new Socket("127.0.0.1",8001);//输出数据String str="见到你很高兴";OutputStream os = socket.getOutputStream();os.write(str.getBytes());//写出一个结束标记socket.shutdownOutput();//接收服务端回写的数据InputStream is = socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);int b;while ((b=isr.read()) !=-1){System.out.println((char) b);}socket.close();}
}
3.2.3 上传文件
Client:
package lx3;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {Socket socket=new Socket("127.0.0.1",9001);//读取本地文件,写到服务端BufferedInputStream bis=new BufferedInputStream(new FileInputStream("day6\\clientdir\\331.jpg"));BufferedOutputStream bos=new BufferedOutputStream(socket.getOutputStream());byte[] bytes=new byte[1024];int len;while ((len=bis.read(bytes)) !=-1){bos.write(bytes,0,len);}//往服务器写出结束标记socket.shutdownOutput();//接收服务器回写数据BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));String s = br.readLine();System.out.println(s);//关闭资源socket.close();}
}
Server:
package lx3;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;public class Server {public static void main(String[] args) throws IOException {ServerSocket ss=new ServerSocket(9001);//等待连接Socket socket = ss.accept();//读取数据并保存到本地文件BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());String name= UUID.randomUUID().toString().replace("-","");//生成一个随机且唯一的idBufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("day6\\serverdir\\"+name+".jpg"));byte[] bytes=new byte[1024];int len;while ((len=bis.read(bytes)) !=-1){bos.write(bytes,0,len);}//回写数据BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();socket.close();ss.close();}
}
3.2.4 上传文件(多线程版)
Server:
package lx3;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;public class Server {public static void main(String[] args) throws IOException {ServerSocket ss=new ServerSocket(9001);while (true) {//等待连接Socket socket = ss.accept();//开启一条线程//一个用户就对应服务端的一条线程new Thread(new MyRunnable(socket)).start();}}
}
Client:
package lx3;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {Socket socket=new Socket("127.0.0.1",9001);//读取本地文件,写到服务端BufferedInputStream bis=new BufferedInputStream(new FileInputStream("day6\\clientdir\\331.jpg"));BufferedOutputStream bos=new BufferedOutputStream(socket.getOutputStream());byte[] bytes=new byte[1024];int len;while ((len=bis.read(bytes)) !=-1){bos.write(bytes,0,len);}//往服务器写出结束标记socket.shutdownOutput();//接收服务器回写数据BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));String s = br.readLine();System.out.println(s);//关闭资源socket.close();}
}
MyRunnable:
package lx3;import java.io.*;
import java.net.Socket;
import java.util.UUID;public class MyRunnable implements Runnable{Socket socket;public MyRunnable (Socket socket){this.socket=socket;}@Overridepublic void run() {try {//读取数据并保存到本地文件BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());String name= UUID.randomUUID().toString().replace("-","");//生成一个随机且唯一的idBufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("day6\\serverdir\\"+name+".jpg"));byte[] bytes=new byte[1024];int len;while ((len=bis.read(bytes)) !=-1){bos.write(bytes,0,len);}//回写数据BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();} catch (IOException e) {throw new RuntimeException(e);} finally {if (socket!=null){try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
线程池的服务端:
package lx3;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class Server {public static void main(String[] args) throws IOException {ThreadPoolExecutor pool=new ThreadPoolExecutor(3,//核心线程数16,//线程池总大小60,//空闲时间TimeUnit.SECONDS,//单位new ArrayBlockingQueue<>(2),//阻塞队列Executors.defaultThreadFactory(),//线程工厂,线程池如何创建线程对象new ThreadPoolExecutor.AbortPolicy()//阻塞队列);ServerSocket ss=new ServerSocket(9001);while (true) {//等待连接Socket socket = ss.accept();//开启一条线程//一个用户就对应服务端的一条线程// new Thread(new MyRunnable(socket)).start();pool.submit(new MyRunnable(socket));}}
}
3.2.5 BS架构
浏览器中输入:127.0.0.1:端口号
运行服务端接收浏览器传的数据
3.2.6 聊天室
Client:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 8003);System.out.println("服务器已经连接成功");//最里面是字节流转换为字符流包裹在缓冲流中BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));while (true) {System.out.println("--------------欢迎来到黑马聊天室--------------");System.out.println("1.登录");System.out.println("2.注册");System.out.println("输入您的选择:");Scanner sc = new Scanner(System.in);String choose = sc.nextLine();switch (choose) {case "1" : login(socket);break;case "2" : System.out.println("用户选择注册");break;default : System.out.println("没有这个选项");break;}}}public static void login(Socket socket) throws IOException {//获取输出流BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//键盘录入Scanner sc=new Scanner(System.in);System.out.println("请输入用户名");String username=sc.nextLine();System.out.println("请输入密码");String password=sc.nextLine();//拼接//格式: username=zhangsan&password=123StringBuilder sb=new StringBuilder();sb.append("username=").append(username).append("&password=").append(password);//第一次写的是什么操作,登录或者注册bw.write("login");bw.newLine();bw.flush();//第二次写的是用户名和密码bw.write(sb.toString());bw.newLine();bw.flush();//获取输入流BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));String message = br.readLine();//根据回写的数据不同,做出不同操作//1.登录成功 2.密码有误 3.用户名不存在if ("1".equals(message)){System.out.println("登录成功,开始聊天");//开一条单独的线程,专门用来接收服务端发送过来的聊天记录new Thread(new ClientMyRunnable(socket)).start();//开始聊天talk2All(bw);}else if ("2".equals(message)){System.out.println("密码有误");} else if ("3".equals(message)) {System.out.println("用户名不存在");}}//往服务器写出消息private static void talk2All(BufferedWriter bw) throws IOException {Scanner sc=new Scanner(System.in);while (true){System.out.println("请输入您要说的话");String str = sc.nextLine();//把聊天内容写给服务器bw.write(str);bw.newLine();bw.flush();}}
}class ClientMyRunnable implements Runnable{Socket socket;public ClientMyRunnable(Socket socket){this.socket=socket;}@Overridepublic void run() {while (true) {try {//接收服务器发过来的聊天记录BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine();System.out.println(msg);} catch (IOException e) {throw new RuntimeException(e);}}}
}
Server:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Properties;public class Server {static ArrayList<Socket> list=new ArrayList<>();public static void main(String[] args) throws IOException {ServerSocket ss=new ServerSocket(8003);//1.获取本地正确的用户名和密码Properties prop=new Properties();FileInputStream fis=new FileInputStream("chat\\a.txt");prop.load(fis);//加载数据fis.close();//2.接收客户端的数据,并进行判断while (true){Socket socket = ss.accept();new Thread(new MyRunnable(socket,prop)).start();}}
}class MyRunnable implements Runnable{Socket socket;Properties prop;MyRunnable(Socket socket,Properties prop){this.prop=prop;this.socket=socket;}@Overridepublic void run() {//接收用户发送的数据try {BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));while (true) {String choose = br.readLine();//第一次读取switch (choose){case "login" :login(br);break;case "register": register();}}} catch (IOException e) {throw new RuntimeException(e);}}//获取用户登录的信息,并判断是否正确public void login (BufferedReader br) throws IOException {//第二次读取String userinfo = br.readLine();String[] userInfoArr = userinfo.split("&");String usernameInput=userInfoArr[0].split("=")[1];String passwordInput=userInfoArr[1].split("=")[1];//判断用户名是否存在if (prop.containsKey(usernameInput)){String rightPassword = prop.get(usernameInput) + "";if (rightPassword.equals(passwordInput)){//提示用户登录成功,开始聊天writeMessagetoClient("1");//登陆成功时,把客户端连接到的Socket对象保存起来Server.list.add(socket);//写一个while循环表示正在聊天//接收客户端发送的消息,并打印在控制台//写成一个方法talkAll(br,usernameInput);while (true){}}else {//密码有误writeMessagetoClient("2");}}else {//用户名不存在writeMessagetoClient("3");}}private void talkAll(BufferedReader br,String username) throws IOException {while (true){String message = br.readLine();System.out.println(username+"发送过来消息"+message);//群发操作for (Socket s : Server.list) {//s依次表示每一个客户端的连接对象writeMessagetoClient(s,username+"发送过来消息"+message);}}}//给客户端回写数据public void writeMessagetoClient(String message) throws IOException {BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}public void writeMessagetoClient(Socket s, String message) throws IOException {BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}public void register(){}}
(四)、反射
反射允许对成员变量,成员方法,构造方法的信息进行编程访问
4.1 获取class对象三种方法
1.Class.forName(“全类名”);
全类名:包名+类名
2.类名.class
3.对象.getClass()
package reflect1;public class r1 {public static void main(String[] args) throws ClassNotFoundException {//方式1//最常用Class class1 = Class.forName("reflect1.Student");//方式2//一般当做参数传递Class class2 = Student.class;//方式3//已经有了这个类的对象时,才会使用Student s=new Student();Class class3 = s.getClass();}
}
4.2 反射获取
获取构造方法:
setAccessible(true):临时取消权限校验(暴力反射)
getDeclaredConstructor():里面的参数要与需要获取的方法里的形参一致,如:int.class
getModifiers():获取权限修饰符,返回的整数
获取成员变量:
package reflect;import java.lang.reflect.Field;public class f1 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {Class clazz = Class.forName("reflect.Student");//获取单个成员变量Field name = clazz.getDeclaredField("name");System.out.println(name);//获取权限修饰符int modifiers = name.getModifiers();System.out.println(modifiers);//获取成员变量名字String n = name.getName();System.out.println(n);//获取成员变量的数据类型Class<?> type = name.getType();System.out.println(type);//获取成员变量记录的值Student s=new Student("zhangsan",23,"男");name.setAccessible(true);String value=(String)name.get(s);System.out.println(value);//修改对象里面记录的值name.set(s,"lisi");//将s对象里的名字修改成lisiSystem.out.println(s);}
}
获取成员方法:
package reflect3;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;public class r3 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {Class clazz = Class.forName("reflect3.Student");//获取所有方法对象(包含父类中的所有方法)//getDeclaredMethods可以获取私有的方法,但不能获取到父类的方法Method[] methods = clazz.getMethods();for (Method method : methods) {System.out.println(method);}//获取指定单一方法Method m = clazz.getDeclaredMethod("eat", String.class);System.out.println(m);//获取修饰符int modifiers = m.getModifiers();System.out.println(modifiers);//获取名字String name = m.getName();System.out.println(name);//获取方法形参Parameter[] parameters = m.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}//获取方法抛出的异常Class[] exceptionTypes = m.getExceptionTypes();for (Class exceptionType : exceptionTypes) {System.out.println(exceptionType);}//方法运行 invoke//参数一:用obj对象调用该方法//参数二:调用方法的传递的参数(如果没有就不写)//返回值:方法的返回值(如果没有就不写)Student stu=new Student();m.setAccessible(true);//参数一s:表示方法的调用者//参数二"汉堡包":表示在调用方法的时候传递的实际参数m.invoke(stu,"汉堡");}
}
4.3 练习
练1:对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
package reflect4;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;public class l1 {public static void main(String[] args) throws IllegalAccessException, IOException {Student s=new Student("aaa",20,"女",167.5,"睡觉");Teacher t=new Teacher("波妞",10000);saveObject(s);}public static void saveObject(Object obj) throws IllegalAccessException, IOException {//获得字节码文件的对象Class clazz = obj.getClass();//创建IO流,保存数据BufferedWriter bw=new BufferedWriter(new FileWriter("day6\\a.txt"));//2.获取所有成员变量Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//获取名字String name = field.getName();//获取值Object value = field.get(obj);//写出数据bw.write(name+"="+value);bw.newLine();}bw.close();}
}
练2:
动态创建对象,并调用方法
package reflect5;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1,读取配置文件的信息Properties prop=new Properties();FileInputStream fis=new FileInputStream("day6\\prop.properties");prop.load(fis);//把数据读取到数组当中fis.close();//2.获取全类名和方法名String classname = (String) prop.get("classname");String Methodname = (String) prop.get("method");//利用反射创建对象并运行方法Class clazz = Class.forName(classname);//获取构造方法,创建对象Constructor con = clazz.getDeclaredConstructor();Object o = con.newInstance();//获取成员方法并运行Method Method = clazz.getDeclaredMethod(Methodname);Method.setAccessible(true);Method.invoke(o);}
}
配置文件:
classname=reflect5.Teacher
method=teach
(五)、动态代理
无侵入式的给代码添加额外功能
对象想有什么方法被代理,代理就一定要有对应的方法
需要被代理的方法放在接口中。对象和代理都要实现同一个接口
创建代理对象:
ProxyUtil:
package daili;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil implements star{//给一个明星的对象,创建一个代理//形参:被代理的明星对象//返回值:给明星创建的代理public static star createProxy(bigstar bigstar){star star= (star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类new Class[]{star.class},//参数二:指定接口,这些接口含有需要被代理的方法//生成的代理对象要干什么事情new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/** 参数一:代理的对象* 参数二:要运行的方法* 参数三:调用sing方法,传递的实参* */if ("sing".equals(method.getName())){System.out.println("准备话筒,收钱");}else if ("dance".equals(method.getName())){System.out.println("准备场地,收钱");}//开始唱歌或跳舞return method.invoke(bigstar,args);}});return star;}@Overridepublic String sing(String name) {return null;}@Overridepublic void dance() {}
}
Test:
package daili;public class Test {public static void main(String[] args) {/** 需求:* 外面的人想要明星唱歌* 1.获取代理的对象* 代理对象=ProxyUtil.createProxy(明星对象);* 2.再调用代理的唱歌方法* 代理对象.唱歌的方法(“只因你太美”);* */bigstar bigstar=new bigstar("鸡哥");star proxy = ProxyUtil.createProxy(bigstar);String result = proxy.sing("只因");System.out.println(result);}
}
bigstar:
package daili;public class bigstar implements star{private String name;public bigstar() {}public bigstar(String name) {this.name = name;}//唱歌跳舞@Overridepublic String sing(String name ){System.out.println(this.name+"正在唱"+name);return "谢谢";}@Overridepublic void dance(){System.out.println(this.name+"正在跳舞");}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}public String toString() {return "bigstar{name = " + name + "}";}
}
star接口:
package daili;public interface star {public abstract String sing(String name );public abstract void dance();
}
相关文章:

Java10
Java10 (一)、配置文件(二)、多线程2.1 并发和并行2.2 多线程的实现方式2.3 常见成员方法2.3.1 线程的优先级2.3.2 守护线程(备胎线程)2.3.3 礼让线程和插入线程 2.4 线程生命周期2.5 线程安全问题2.6 锁2.…...

IMS call通话类型对比差异
IMS call呼入/呼出流程对比 呼出MO call大致流程 1)UE发送INVITE消息发起IMS call 2)UE接收网络返回的100 Trying 3)UE接收183 Session Progress 4)UE发送PRACK确认收到183 5)UE接收200 OK(PRACK) 6)UE发送UPDATE进行precondition流程 7)UE接收200 OK(UPDATE) 8…...

5.2 中心极限定理
学习目标: 要学习中心极限定理,我会采取以下几个步骤: 学习基本概念:了解什么是随机变量、样本、总体、概率密度函数等基本概念,为学习中心极限定理打下基础;学习正态分布:中心极限定理的核心…...

JVM 内存分哪几个区,如和判断一个对象是否存活
JVM 内存分哪几个区,每个区的作用是什么? java 虚拟机主要分为以下一个区:方法区: 1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生 GC,在这里进行的 GC 主要是对方法区里的常量池和对类型…...

在Spring Boot微服务使用Jedis操作Redis List列表
记录:408 场景:在Spring Boot微服务使用Jedis操作Redis List列表。 版本:JDK 1.8,Spring Boot 2.6.3,redis-6.2.5,jedis-3.7.1。 1.微服务中配置Redis信息 1.1在application.yml中Jedis配置信息 hub:example:redis:jedis:host: 192.168.…...

springboot + vue 部署 阿里云云服务器 ECS
安装所需文件 安装mysql5.7 下载MySQL的yum源配置 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm安装MySQL的yum源 yum -y install mysql57-community-release-el7-11.noarch.rpm使用yum方式安装MySQL5.7(下载需要点时间…...

mysql 日期 计算 时间差 天数差
mysql计算两个日期的时间差 第一种:TIMESTAMPDIFF函数 三个参数。第一个参数是比较的类型:FRAC_SECOND、SECOND、 MINUTE、 HOUR、 DAY、 WEEK、 MONTH、 QUARTER、YEAR几种类型。第二、三参数是时间,后减前: SELECT TIMESTAMPDIFF(DAY,20…...

不用网闸、FTP的话 如何实现内外网数据交换?
网络隔离已然成为很多企业首选的数据保护方式,即使是内部人员之间,也是不能随意的发送敏感文件的。但是,文件的流转交互,又是不可避免的,网络隔离保障了企业网络安全,但在具体实践中仍需解决各隔离网间的数…...

探寻Spring MVC的奥秘:内部组件与工作流程详解
Spring MVC是一个基于MVC架构模式的Web框架,是Spring框架的一个组件。它提供了一套Web应用程序开发的全面解决方案,包括从请求到响应的处理流程、处理请求的控制器、视图解析器、国际化和验证器等。 在这篇文章中,我们将介绍Spring MVC框架的…...

eclipse svn ClassNotFoundException: javassist.ClassPool
eclipse 五月 10, 2023 9:26:49 上午 org.apache.catalina.core.StandardContext filterStart 严重: Exception starting filter struts2 java.lang.reflect.InvocationTargetException - Class: com.opensymphony.xwork2.inject.ContainerImpl M e t h o d I n j e c t o r F…...

广度优先遍历搜索迷宫最短路径
思路分析 由于广度是扩散逐层的方式遍历,相当于是多条路同时跑,最后先到终点就是最短路径了。 广度优先搜索主要使用队列来进行处理 路径用一个单独的vector存储,每一个点的坐标由二维转为一维,如(2, 3)存储在vector中下标为2*…...

分布式计算基础知识
分布式系统的概念 分布式系统是由多个独立计算机组成的系统,这些计算机通过网络进行通信和协作,共同完成一个任务。分布式系统的特点是具有高可用性、可扩展性和容错性。 在分布式系统中,每个计算机节点都可以独立地执行任务,同…...

Mybatis方式完成CRUD操作
Mybatis方式完成CRUD操作 文章目录 Mybatis方式完成CRUD操作1、java以Mybatis方式操作DB1.1、配置数据源-创建 resources/mybatis-config.xml1.2、创建java bean-Monster1.3、配置Mapper接口声明方法1.4、配置xxMapper,完成SQL配置,实现CRUD操作1.5、Test测试 2、需…...

css背景 background的属性作用和值
当我们在 HTML 中设置背景时,可以使用 background 属性。这个属性有多个值,可以使用不同的值来设置背景图片、背景颜色、背景位置、背景重复等等。以下是用表格列出的常见的 background 属性的值及其作用: 属性值描述background-color设置背…...

六大行文化特色知识(上)
中国六大银行都是综合性大型商业银行,业务涵盖面广泛且多元,代表着中国金融界最雄厚的资本和实力,这也是为什么很多毕业生想进国有行的原因,今天小编就带大家来了解一下关于六大行的特色知识,从如信银行考试中心平台了…...

匿名对象的特性和使用场景你知道吗?
目录 一、匿名对象的概念 二、单参数和多参数构造场景的匿名对象 ①只有一个参数的构造函数 ②多个参数的构造函数 三、使用匿名对象作为函数的参数的缺省值 四、只为调用类中的一个函数时 五、匿名对象的特性 1、匿名对象的生命周期只有一行 2、匿名对象具有常性 3、当匿…...

企业应该如何做到数字化转型成功?
01 成长型企业数字化转型的意义 成长型企业想要实现数字化转型,那么我们需要先弄明白,对于成长型企业而言,数字化转型到底具有什么意义?希望实现哪些目标? 可以归结为以下四点: 提升企业的生产力和效率&…...

PBDB Data Service:Bibliographic references for fossil collections(采集记录参考书目)
Bibliographic references for fossil collections(采集记录参考书目) 描述用法参数以下参数可用于检索与通过各种条件选择的集合关联的引用您可以使用以下参数根据书目参考文献的属性筛选结果集以下参数也可用于筛选选择以下参数可用于根据所选匹配项的…...

浅析图形验证码安全
0x01 前言 验证码的定义: 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的…...

论文笔记:基于手机位置信息的地图匹配算法
2015计算机应用 整体思路和论文笔记:Hidden Markov Map MatchingThrough Noise and Sparseness_UQI-LIUWJ的博客-CSDN博客 很像,也是应用HMM进行地图匹配 HMMM本文 状态转移矩阵 观测概率矩阵 正态分布均值都是0,唯一不同的是S…...

因果推断系列16-面板数据与固定效应
因果推断系列16-面板数据与固定效应 1.平行趋势2.未观测变量的控制3.固定效应4.固定效应可视化5.时间效应小结加载第三方包 import warnings warnings.filterwarnings(ignore)import pandas as pd import numpy as np from matplotlib import style from matplotlib import...

第三十三章 弹性池塘2(弹城少年歌词)
熟悉的K26,熟悉的漉菽香味,熟悉的絮絮叨叨。 为什么坎迪总有那么多话想说,就算恢复正常,自己应该也找不出如滔滔江水连绵不断的语词洪流吧。 不,不是词汇量的问题。 当你习惯于将金玉良言与废屁空套话区分开来时&#…...

PMP之预测部分
引论 什么是项目 项目是为创造独特的产品、服务或成果而进行的临时性工作。 项目管理是把事办成的方法论,万物皆可项目。 项目的基本要素 项目(独特性、临时性)、驱动变更、启动背景、创造商业价值。 组织级项目管理(OPM&am…...

Node.js 异步流控制
目录 1、简介 2、状态管理 3、控制流 3.1、串联 3.2、完全并行 3.3、有限并行 1、简介 在其核心,JavaScript被设计为在“主”线程上是非阻塞的,这是呈现视图的位置。你可以想象这在浏览器中的重要性。例如,当主线程被阻塞时࿰…...

掌握这些思维技巧,解救996的打工人!
你身边有没有这样的人:面对堆积如山的工作、随时弹出的任务,接二连三的群也能游刃有余地处理。回看自己,旧的任务还在做,新的任务已经从天而降,日程表上满是任务却无从下手…… 明明忙个不停却成果甚微,这…...

【嵌入式Linux】MBR分区表 和 GPT分区表
文章目录 GUID以及分区表MBR分区方案GPT 分区方案GPT分区表结构 GPT分区表LBALBA0(MBR兼容部分)LBA1LBA 2-33python生成GPT分区表gpt分区表实例 gpt分区表查看查看百问网T113-s3固件查看友善之臂nanopi-m1-plus官方固件查看荣品RV1126固件查看f1c200s固件…...

【华为OD机试真题】MVP争夺战(python)100%通过率 超详细代码注释 代码解读
【华为OD机试真题 2022&2023】真题目录 @点这里@ 【华为OD机试真题】信号发射和接收 &试读& @点这里@ 【华为OD机试真题】租车骑绿道 &试读& @点这里@ MVP争夺战 知识点DFS搜索 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 在星球争霸篮球赛对…...

实战打靶集锦-019-BTRSys2.1
提示:本文记录了博主的一次普通的打靶经历 目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 FTP服务探查4.2 Apache服务探查4.2.1 wpscan扫描4.2.2 Metasploit神器4.2.3 手工探查页面4.2.3.1 Appearance Editor4.2.3.2 Plugins Editor 5. 提权5.1 系统信息枚…...

2023中国(苏州)国际电源工业展览会暨高端论坛
时间:2023年11月9~11日 地点:苏州国际博览中心 30000㎡展出面积 500参展商 50000名专业观众 中国电源行业风向标----相约苏州,共襄盛举! ◆展会背景Exhibition background: …...

基于SpringBoot+Vue的校园疫情防控系统(附源码和数据库)
文章目录 第一章2.主要技术第三章第四章 系统设计4.1功能结构4.2 数据库设计4.2.1 数据库E/R图4.2.2 数据库表 第五章 系统功能实现5.1系统功能模块5.2后台功能模块5.2.1管理员功能 源码咨询 第一章 springboot校园疫情防控系统演示录像2022 一个好的系统能将校园疫情防控的管理…...