文章目录
- 多线程
- 线程的状态
- 线程池
- 自定义线程池
- 最大并行数
- 多线程小练习
- 网络编程
- BS架构优缺点
- CS架构优缺点
- 三要素
- IP
- 特殊IP
- 常用的CMD命令
- InetAddress类
- 端口号
- 协议
- UDP协议(重点)
- UDP三种通信方式
- TCP协议(重点)
- 三次握手
- 四次挥手
- 反射
- 获取class的三种方式
- 利用反射获取构造方法
- 反射的作用
- 动态代理
- 注解
- 自定义注解
- 元注解
- 什么是注解的解析?
- 如何解析注解?
多线程
线程的状态
新建状态(NEW)—创建线程对象
就绪状态(RUNNABLE)—start方法
阻塞状态(BLOCKED)—无法获得锁对象
等待状态(WAITING)—wait方法
计时等待(TIMED WAITING)—sleep方法
结束状态(TERMINATED)—全部代码运行完毕
线程池
- 创建一个池子,池子中是空的
- 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子
下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可 - 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
Executors
:线程池的工具类通过调用方法返回不同类型的线程池对象
方法名称 | 说明 |
---|---|
public static ExecutorService newCachedThreadPool() | 创建一个没有上限的线程池 |
public static ExecutorService newFixedThreadPool(int nThreads) | 创建有上限的线程池 |
无上限
public class demo1 {public static void main(String[] args) throws InterruptedException {ExecutorService pool1 = Executors.newCachedThreadPool();pool1.submit(new MyRunable());Thread.sleep(1000);pool1.submit(new MyRunable());Thread.sleep(1000);pool1.submit(new MyRunable());Thread.sleep(1000);pool1.submit(new MyRunable());Thread.sleep(1000);pool1.submit(new MyRunable());pool1.shutdown();}
}
public class MyRunable implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "hhh");
有上限
public class demo1 {public static void main(String[] args) throws InterruptedException {ExecutorService pool1 = Executors.newFixedThreadPool(3);pool1.submit(new MyRunable());pool1.submit(new MyRunable());pool1.submit(new MyRunable());pool1.submit(new MyRunable());pool1.submit(new MyRunable());pool1.shutdown();}
}
自定义线程池
任务拒绝策略 | 说明 |
---|---|
ThreadPoolExecutor.AbortPolicy | 默认策略:丢弃任务并抛出RejectedExecutionException异常 |
ThreadPoolExecutor.DiscardPolicy | 丢弃任务,但是不抛出异常 这是不推荐的做法 |
ThreadPoolExecutor.DiscardOldestPolicy | 抛弃队列中等待最久的任务 然后把当前任务加入队列中 |
ThreadPoolExecutor.CallerRunsPolicy | 调用任务的run()方法绕过线程池直接执行 |
参数 | 说明 | 要求 |
---|---|---|
corePoolSize | 核心线程数量 | 不能小于0 |
maximumPoolSize | 最大线程数量 | 不能小于0,最大数量 >= 核心线程数量 |
keepAliveTime | 空闲线程最大存活时间 | 不能小于0 |
unit | 时间单位 | 用TimeUnit 指定 |
workQueue | 任务队列 | 不能为null |
threadFactory | 创建线程工厂 | 不能为null |
handler | 任务的拒绝策略 | 不能为null |
public class demo1 {public static void main(String[] args) {ThreadPoolExecutor pool = new ThreadPoolExecutor(3,6,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}
}
最大并行数
public class demo1 {public static void main(String[] args) {System.out.println(Runtime.getRuntime().availableProcessors());}
}
多线程小练习
一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒
(要求:请用多线程模拟卖票过程并打印剩余电影票的数量)
package practices.a01;public class MyThread extends Thread{static int ticket = 1000;@Overridepublic void run() {while (true){synchronized (MyThread.class) {if (ticket == 0)break;else{ticket--;System.out.println(getName() + "卖出了一张票,还剩" + ticket + "张");}}}}
}
public class demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("窗口1");t2.setName("窗口2");t1.start();t2.start();}
}
网络编程
在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
- 应用场景:即时通信、网游对战、金融证券、国际贸易、邮件、等等。
不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输, - Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。
BS架构优缺点
- 不需要开发客户端,只需要页面+服务端
- 用户不需要下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
CS架构优缺点
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务端
- 用户需要下载和更新的时候太麻烦
三要素
IP
:设备在网络中的地址,是唯一的标识。
端口号
:应用程序在设备中唯一的标识。
协议
:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。
IP
全称:Internet Protocol,是互联网协议地址,也称IP地址。
是分配给上网设备的数字标签
通俗理解
:上网设备在网络中的地址,是唯一的
常见的IP分类
为 :IPv4、IPv6
特殊IP
127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。
常用的CMD命令
ipconfig
:查看本机IP地址
ping
:检查网络是否连通
InetAddress类
public class MyInetAddressDemo1 {public static void main(String[] args) throws UnknownHostException {//1.获取InetAdderss对象// 获取本地主机的 InetAddress 对象InetAddress address1 = InetAddress.getLocalHost();System.out.println("本地主机信息:" + address1);System.out.println("本地主机名:" + address1.getHostName());System.out.println("本地 IP 地址:" + address1.getHostAddress());// 根据主机名获取 InetAddress 对象InetAddress address2 = InetAddress.getByName("xuanlaptop");System.out.println("指定主机信息:" + address2);System.out.println("主机名:" + address2.getHostName());System.out.println("IP 地址:" + address2.getHostAddress());}
}
端口号
应用程序在设备中唯一的标识。
端口号:由两个字节表示的整数,取值范围:0~65535
其中0~1023之间的端口号用于一些知名的网络服务或者应用
我们自己使用1024以上的端口号就可以了
注意:一个端口号只能被一个应用程序使用。
协议
计算机网络中,连接和通信的规则被称为网络通信协议
- OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
- TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
UDP协议(重点)
- 用户数据报协议(User Datagram Protocol)
- UDP是
面向无连接通
信协议。
速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
发送数据
package udpPractices.a01;import java.io.IOException;
import java.net.*;public class demo1 {public static void main(String[] args) throws IOException {//创建DatagramSocket对象(快递公司)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();}
}
接收数据
package udpPractices.a01;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class demo2 {public static void main(String[] args) throws IOException {//创建DatagramSocket对象(快递公司)DatagramSocket ds = new DatagramSocket(10086);//接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);ds.receive(dp);//解析数据包byte[] data = dp.getData();int len = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到数据:" + new String(data, 0, len) + '\n' + "该数据是从" + address + "这台电脑" + port + "这个端口发出的");//释放资源ds.close();}
}
聊天室
-
发送消息
package udpPractices.a01;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Scanner;public class demo1 {public static void main(String[] args) throws IOException {//创建DatagramSocket对象(快递公司)DatagramSocket ds = new DatagramSocket();Scanner sc = new Scanner(System.in);//打包数据while (true) {System.out.print("请输入您要说的话:");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 udpPractices.a01;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;public class demo2 {public static void main(String[] args) throws IOException {//创建DatagramSocket对象(快递公司)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 len = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));}//释放资源}
UDP三种通信方式
-
单播:以前的代码就是单播
-
组播:
组播地址
:224.0.0.0~239.255.255.255其中224.0.0.0~224.0.0.255 为预留的组播地址
-
广播:
广播地址
:255.255.255.255
TCP协议(重点)
- 传输控制协议TCP(Transmission Control Protocol)
- TCP协议是面向连接的通信协议,
速度慢,没有大小限制,数据安全,
发送
package udpPractices.a02;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 socket = new Socket("127.0.0.1", 10000);//从连接通道中获取输出流OutputStream os = socket.getOutputStream();//写出数据os.write("aaa".getBytes());//释放资源os.close();socket.close();}
}
接收
package udpPractices.a02;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 {//创建对象ServerSockerServerSocket ss = new ServerSocket(10000);//监听客户端的连接Socket sorket = ss.accept();//从连接通道中获取输入流读取数据InputStream is = sorket.getInputStream();int b;while((b = is.read()) != -1) {System.out.println((char) b);}//释放资源sorket.close();ss.close();}
}
三次握手
确保连接建立
四次挥手
确保连接断开,且数据处理完毕
反射
反射允许对封装类的字段,方法和构造函数的信息进行编程访问
获取class的三种方式
Class.forName("全类名")
;类名.class
;对象.getclass()
;
public class demo1 {public static void main(String[] args) throws ClassNotFoundException {//1.全类名:包名 + 类名Class clazz1 = Class.forName("myreflect.a01.Student");//2.Class clazz2 = Student.class;//3.Student s = new Student();Class clazz3 = s.getClass();}
}
利用反射获取构造方法
Class类中用于获取构造方法的方法:
方法 | 功能 |
---|---|
Constructor<?>[] getConstructors() | 返回所有公共构造方法对象的数组 |
Constructor<?>[]getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor<T>getConstructor(Class<?>...parameterTypes) | 返回单个公共构造方法对象 |
Constructor<T>getDeclaredConstructor(Class<?>... parameterTypes) | 返回单个构造方法对象 |
package myreflect.a02;import java.lang.reflect.Constructor;public class demo1 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {//1.过去class字节码文件对象Class clazz = Class.forName("myreflect.a02.Student");//2.获取构造方法(公有)Constructor[] cons1 = clazz.getConstructors();for (Constructor con : cons1) {System.out.println(con);}System.out.println("---------------------------");//(所有)Constructor[] cons2 = clazz.getDeclaredConstructors();for (Constructor con : cons2) {System.out.println(con);}System.out.println("---------------------------");//单个.空参Constructor con3 = clazz.getDeclaredConstructor();System.out.println(con3);System.out.println("---------------------------");//单个.实参Constructor con4 = clazz.getDeclaredConstructor(String.class);System.out.println(con4);int modifiers = con4.getModifiers();System.out.println(modifiers);Parameter[] parameters = con4.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}}
}
Constructor类中用于创建对象的方法:
方法 | 功能 |
---|---|
T newlnstance(Object...initargs) | 根据指定的构造方法创建对象 |
setAccessible(boolean flag) | 设置为true,表示取消访问检查 |
package myreflect.a02;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;public class demo2 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class clazz = Class.forName("myreflect.a02.Student");Constructor con = clazz.getDeclaredConstructor(String.class, int.class);//表示临时取消权限校验con.setAccessible(true);Student stu = (Student) con.newInstance("张三", 23);System.out.println(stu);}
}
Class类中用于获取成员变量的方法
方法 | 说明 |
---|---|
Field[] getFields() | 返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
Field getField(String name) | 返回单个公共成员变量对象 |
Field getDeclaredField(String name) | 返回单个成员变量对象 |
Field类中用于创建对象的方法
方法 | 说明 |
---|---|
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 获取值 |
public class demo1 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {//1.获取class字节码文件的对象Class clazz = Class.forName("myreflect.a03.Student");//2.获取所有的成员变量Field[] fields = clazz.getDeclaredFields();for(Field field : fields) {System.out.println(field);}//3.获取单个成员变量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");System.out.println(s);}
}
Class类中用于获取成员方法的方法
方法 | 说明 |
---|---|
Method[] getMethods() | 返回所有公共成员方法对象的数组,包括继承的 |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,不包括继承的 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个公共成员方法对象 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象 |
Method类中用于创建对象的方法
方法 | 说明 |
---|---|
Object invoke(Object obj, Object... args) | 运行方法 参数一: 用obj对象调用该方法 参数二: 调用方法的传递的参数(如果没有就不写) 返回值: 方法的返回值(如果没有就不写) |
public class demo1 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {//1.获取class字节码文件对象Class clazz = Class.forName("myreflect.a04.Student");//获取所有方法对象Method[] methods = clazz.getMethods();for (Method method : methods) {System.out.println(method);}//获取指定单一方法Method m = clazz.getDeclaredMethod("eat", String.class, int.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);}//方法运行Student s = new Student();m.setAccessible(true);String result = (String) m.invoke(s, "111", 11);System.out.println(result);}
}
反射的作用
- 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
- 结合配置文件,动态的创建对象并调用方法
动态代理
特点
:无侵入式的给代码增加额外的功能
- 为什么需要代理?
代理可以无侵入式的给对象增强其他的功能
调用者->代理->对象 - 代理长什么样?
代理里面就是对象要被代理的方法 - Java通过什么来保证代理的样子?
通过接口保证,后面的对象和代理需要实现同一个接口
接口中就是被代理的所有方法
注解
- 就是java代码里的特殊标记,比如:@Override、@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序。
- 注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处。
自定义注解
- 自己定义注解
public @interface 注解名称 {public 属性类型 属性名() default 默认值;
}
- 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的。
- @注解(…):其实就是一个实现类对象,实现了该注解以及Annotation接口。
元注解
- 指的是:修饰注解的注解。
什么是注解的解析?
- 就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来
如何解析注解?
- 指导思想:要解析谁上面的注解,就应该先拿到谁。
- 比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解。
- 比如要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
- Class、 Method、Field,Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
构造方法 | 说明 |
---|---|
public Annotation[] getDeclaredAnnotations() | 获取当前对象上面的注解 |
public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) | 获取指定的注解对象 |
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) | 判断当前对象上是否存在某个注解 |
已经到底啦!!