文章目录
多线程
线程的状态
新建状态(NEW)---创建线程对象
就绪状态(RUNNABLE)---start方法
阻塞状态(BLOCKED)---无法获得锁对象
等待状态(WAITING)---wait方法
计时等待(TIMED WAITING)---sleep方法
结束状态(TERMINATED)---全部代码运行完毕
线程池
- 创建一个池子,池子中是空的
- 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子
下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可 - 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
Executors
:线程池的工具类通过调用方法返回不同类型的线程池对象
方法名称 | 说明 |
---|---|
public static ExecutorService newCachedThreadPool() |
创建一个没有上限的线程池 |
public static ExecutorService newFixedThreadPool(int nThreads) |
创建有上限的线程池 |
无上限
java
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{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "hhh");
有上限
java
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 |
java
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()
);
}
}
最大并行数
java
public class demo1 {
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
多线程小练习
一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒
(要求:请用多线程模拟卖票过程并打印剩余电影票的数量)
java
package practices.a01;
public class MyThread extends Thread{
static int ticket = 1000;
@Override
public 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类
java
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,数据不安全,易丢失数据
发送数据
java
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();
}
}
接收数据
java
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();
}
}
聊天室
-
发送消息
javapackage 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(); } }
-
接收数据
javapackage 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协议是面向连接的通信协议,
速度慢,没有大小限制,数据安全,
发送
java
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();
}
}
接收
java
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 {
//创建对象ServerSocker
ServerSocket 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()
;
java
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) |
返回单个构造方法对象 |
java
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,表示取消访问检查 |
java
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) |
获取值 |
java
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对象调用该方法 参数二: 调用方法的传递的参数(如果没有就不写) 返回值: 方法的返回值(如果没有就不写) |
java
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等,作用是:让其他程序根据注解信息来决定怎么执行该程序。
- 注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处。
自定义注解
- 自己定义注解
java
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) |
判断当前对象上是否存在某个注解 |
已经到底啦!!