线程池与反射
目录
一、手动创建线程池
1.线程池的执行流程
2.案例
二、Reflection反射
1.Class类
1.1 概述
1.2 Class类
1.3 Class常用方法
一、手动创建线程池
1.线程池的执行流程
(1)提交一个新线程任务,线程池会在线程池中分配一个空闲线程,用于执行线程任务。
(2)如果线程池中不存在空闲线程,则线程池会判断当前”存活的线程数“是否小于核心线程数corePoolSize。
(3)如果小于核心线程数corePoolSize,线程池会创建一个新线程(核心线程)去处理新线程任务。如果大于核心线程数corePoolSize,线程池会检查工作队列。
(4)如果工作队列未满,则将该线程任务放入工作队列进行等待。线程池中如果出现空闲线程,将从工作队列中按照FIFO的规则取出1个线程任务并分配执行。如果工作队列已满,则判断线程数是否达到最大线程数maximumPoolSize。
(5)如果当前”存活线程数“没有达到最大线程数maximumPoolSize,则创建一个新线程(非核心线程)执行新线程任务。如果当前”存活线程数“已经达到最大线程数maximumPoolSize,直接采用拒绝策略处理新线程任务。
综上所述,执行顺序为:核心线程、工作队列、非核心线程、拒绝策略。
int corePoolSize, 核心线程数量>0 int maximumPoolSize, 最大线程数(核心+临时)>corePoolSize long keepAliveTime, 临时线程存活时间 TimeUnit unit, 存活的时间单位 BlockingQueue<Runnable> workQueue, 等待队列 ThreadFactory threadFactory, 线程工厂 RejectedExecutionHandler handler 拒绝策略-----ThreadPoolExecutor.AbortPolicy() 默认拒绝策略--抛异常-----ThreadPoolExecutor.DiscardOldestPolicy() 丢弃等待时间最久的任务-----ThreadPoolExecutor.DiscardPolicy(); 拒绝最后来的任务-----ThreadPoolExecutor.CallerRunsPolicy();让当前的线程进行任务执行
2.案例
案例1:
ExecutorService es = new ThreadPoolExecutor(3, 5, 60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(),
// new ThreadPoolExecutor.AbortPolicy()
// new ThreadPoolExecutor.DiscardOldestPolicy()
// new ThreadPoolExecutor.DiscardPolicy()new ThreadPoolExecutor.CallerRunsPolicy());//提交任务给es对象es.execute(new MyRun("任务1"));//提交一个任务给es对象es.submit(new MyRun("任务2"));es.submit(new MyRun("任务3"));es.submit(new MyRun("任务4"));//核心线程已满,进入等待队列es.submit(new MyRun("任务5"));es.submit(new MyRun("任务6"));es.submit(new MyRun("任务7"));//核心线程已满,等待队列已满,进入临时线程es.submit(new MyRun("任务8"));es.submit(new MyRun("任务9"));//核心线程已满,等待队列已满,临时线程已满,进入拒绝策略es.submit(new MyRun("任务10"));
ArrayBlockingQueue<>与LinkedBlockingQueue<>的使用:
public class Demo07 {public static void main(String[] args) {
// ArrayBlockingQueue<String> abq=new ArrayBlockingQueue<>(3);
// abq.offer("张三");
// abq.offer("李四");
// abq.offer("王五");
//
// System.out.println(abq);
//// abq.remove("张三");
// //取出第一个元素并出栈
// abq.poll();
// //取出第一个元素,但不出栈
//// abq.peek();
// abq.offer("赵六");
// System.out.println(abq);LinkedBlockingQueue<String> lbq=new LinkedBlockingQueue<>();lbq.offer("张三");lbq.offer("李四");lbq.offer("王五");lbq.offer("赵六");System.out.println(lbq);}
}
案例2:重写线程工厂ThreadFactory和拒绝策略RejectedExecutionHandler
ExecutorService es = new ThreadPoolExecutor(3, 5, 60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),
// Executors.defaultThreadFactory(),new MyThreadFactory("用户消费"),new MyRejectedHandler());//提交任务给es对象es.execute(new MyRun("任务1"));//提交一个任务给es对象es.execute(new MyRun("任务2"));es.execute(new MyRun("任务3"));es.execute(new MyRun("任务4"));//核心线程已满,进入等待队列es.execute(new MyRun("任务5"));es.execute(new MyRun("任务6"));es.execute(new MyRun("任务7"));//核心线程已满,等待队列已满,进入临时线程es.execute(new MyRun("任务8"));es.execute(new MyRun("任务9"));//核心线程已满,等待队列已满,临时线程已满,进入拒绝策略es.execute(new MyRun("任务10"));}
}
class MyThreadFactory implements ThreadFactory {//线程池名称前缀String namePrefix;public MyThreadFactory(String namePrefix) {this.namePrefix = namePrefix;}//具备原子性的Integer类型private AtomicInteger threadNumber=new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {return new Thread(r, namePrefix+"线程"+threadNumber.getAndIncrement());}
}
//重写拒绝策略
class MyRejectedHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {System.out.println("哎呦达到能执行任务的上线了,你待会再来!");}
}
class MyRun implements Runnable {String str;public MyRun(String str) {this.str = str;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "正在执行" + str);
// try {
// Thread.sleep(1000*5);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName()+"执行结束"+str);while (true) {//死循环,目的验证线程池的执行流程}}
}
二、Reflection反射
1.Class类
1.1 概述
在Java
中,除了int
等基本类型外,Java
的其他类型全部都是class
(包括interface
)。例如:String、Object、Runnable、Exception、...
Java反射机制是Java语言的一个重要特性。在学习Java反射机制前,大家应该先了解两个概念:编译器和运行期。
编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。在Java中也就是把Java代码编成class文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作。比如:检查语法错误。
运行期:是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java
语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java
中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
Java
反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法或者为属性赋值。例如:在主流的 ORM
框架的实现中,运用 Java
反射机制可以读取任意一个 JavaBean
的所有属性,或者给这些属性赋值。
Java反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。
生成动态代理。
1.2 Class类
要想知道一个类的属性和方法,必须先获取到该类的字节码文件对象。获取类的信息时,使用的就是 Class
类中的方法。所以先要获取到每一个字节码文件(.class
)对应的 Class
类型的对象。
class
(包括interface
)的本质是数据类型(Type
)。class
是由JVM
在执行过程中动态加载的。JVM
在第一次读取到一种class
类型时,将其加载进内存。每加载一种class
,JVM
就为其创建一个Class
类型的实例,并关联起来。
注意:这里的Class
类型是一个名叫Class
的class
,定义如下:
// final声明不允许继承
public final class Class {// 私有的构造方法private Class() {}
}
以String
类为例,当JVM
加载String
类时,它首先读取String.class
文件到内存,然后,为String
类创建一个Class
实例并关联起来:
Class cls = new Class(String);
这个Class
实例是JVM
内部创建的,如果我们查看JDK
源码,可以发现Class
类的构造方法是private
,只有JVM
能创建Class
实例,我们自己的Java
程序是无法创建Class
实例的。
所以,JVM
持有的每个Class
实例都指向一个数据类型(class
或interface
):
┌───────────────────────────┐
│ Class Instance │──────> String
├───────────────────────────┤
│name = "java.lang.String" │
└───────────────────────────┘
┌───────────────────────────┐
│ Class Instance │──────> Random
├───────────────────────────┤
│name = "java.util.Random" │
└───────────────────────────┘
┌───────────────────────────┐
│ Class Instance │──────> Runnable
├───────────────────────────┤
│name = "java.lang.Runnable"│
└───────────────────────────┘
一个Class
实例包含了该class
的所有完整信息:
┌───────────────────────────┐
│ Class Instance │──────> String
├───────────────────────────┤
│name = "java.lang.String" │
├───────────────────────────┤
│package = "java.lang" │
├───────────────────────────┤
│super = "java.lang.Object" │
├───────────────────────────┤
│interface = CharSequence...│
├───────────────────────────┤
│field = value[],hash,... │
├───────────────────────────┤
│method = indexOf()... │
└───────────────────────────┘
由于JVM
为每个加载的class
创建了对应的Class
实例,并在实例中保存了该class
的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段(成员变量)等,因此,如果获取了某个Class
实例,我们就可以通过这个Class
实例获取到该实例对应的class
的所有信息。这种通过Class
实例获取class
信息的方法称为反射(Reflection
)。
如何获取一个class
的Class
实例?有三个方法:
方式一:直接通过一个class的静态变量class获取。
方式二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取。
方式三:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取。
//1.获取类的字节码文件对象//方式1:直接通过一个class的静态变量class获取Class clazz1= Person.class;System.out.println(clazz1);//方式2:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取Class clazz2=Class.forName("apesource.knowledge01.Person");System.out.println(clazz2);//方式3:通过具体的对象的getClass()方法获取Person p1=new Person();Class clazz3=p1.getClass();System.out.println(clazz3);
因为Class
实例在JVM
中是唯一的,所以,上述方法获取的Class
实例是同一个实例。可以用==
比较两个Class
实例:
System.out.println(clazz1==clazz2);
System.out.println(clazz2==clazz3);
反射的目的是为了获得某个实例的信息。因此,当我们拿到某个Object
实例时,我们可以通过反射获取该Object
的class
信息:
void printObjectInfo(Object obj) {Class cls = obj.getClass();
}
要从Class
实例获取获取的基本信息,参考下面的代码:
public class Demo02 {public static void main(String[] args) throws ClassNotFoundException {printClassInfo(Class.forName("apesource.knowledge01.Person"));}private static void printClassInfo(Class cls) {System.out.println("Class name:" + cls.getName());System.out.println("Simple name: " + cls.getSimpleName());if (cls.getPackage() != null) {System.out.println("Package name: " + cls.getPackage().getName());}System.out.println("is interface: " + cls.isInterface());System.out.println("is enum: " + cls.isEnum());System.out.println("is array: " + cls.isArray());System.out.println("is primitive: " + cls.isPrimitive());}
}
public class Person implements Serializable, Cloneable {String name;int age;public Person() {}public Person(String name) {this.name = name;}protected Person(int age) {this.age = age;}private Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
注意,数组(例如String[]
)也是一种类,而且不同于String.class
,它的类名是[Ljava.lang.String;
。此外,JVM为每一种基本类型如int
也创建了Class
实例,通过int.class
访问。
如果获取到了一个Class
实例,我们就可以通过该Class
实例来创建对应类型的实例:
// 获取String的Class实例:
Class cls = String.class;// 创建一个String实例:
//要求实例时必须要有公开的无参构造方法,否则报错
String s = (String) cls.newInstance();
//Object o1=cls.newInstance();
上述代码相当于new String()
。通过Class.newInstance()
可以创建类实例,它的局限是:只能调用public
的无参数构造方法。带参数的构造方法,或者非public的构造方法都无法通过Class.newInstance()
被调用。
1.3 Class常用方法
类型 | 访问方法 | 返回值类型 | 说明 |
包路径 | getPackage() | Package 对象 | 获取该类的存放路径 |
类名称 | getName() | String 对象 | 获取该类的名称 |
继承类 | getSuperclass() | Class 对象 | 获取该类继承的类 |
实现接口 | getlnterfaces() | Class 型数组 | 获取该类实现的所有接口 |
构造方法 | getConstructors() | Constructor 型数组 | 获取所有权限为 public 的构造方法 |
getDeclaredContruectors() | Constructor 对象 | 获取当前对象的所有构造方法 | |
方法 | getMethods() | Methods 型数组 | 获取所有权限为 public 的方法 |
getDeclaredMethods() | Methods 对象 | 获取当前对象的所有方法 | |
成员变量 | getFields() | Field 型数组 | 获取所有权限为 public 的成员变量 |
getDeclareFileds() | Field 对象 | 获取当前对象的所有成员变量 |
public class Demo03 {public static void main(String[] args) {Class clazz=Person.class;//包路径 getPackage() Package对象 获取该类的存放路径Package pac=clazz.getPackage();System.out.println(pac);//类名称 getName() String对象 获取该类的名称String strName=clazz.getName();System.out.println(strName);//继承类 getSuperclass() Class对象 获取该类继承的类Class supclass=clazz.getSuperclass();System.out.println(supclass);//实现接口 getInterfaces() Class型数组 获取该类实现的所有接口Class[] cles=clazz.getInterfaces();System.out.println(Arrays.toString(cles));}
}
public class Demo04RefConstructors {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1.获取类的字节码文件对象Class clazz=Person.class;//2.获取构造方法// 2.1 getConstructors获取所有被public修饰的构造方法
// Constructor[] cons=clazz.getConstructors();
// for(Constructor con:cons){
// System.out.println(con);
// }//2.2 getDeclaredConstructors获取所有构造方法Constructor[] cons=clazz.getDeclaredConstructors();for(Constructor con:cons){System.out.println(con);}System.out.println("====================");//2.3 getConstructor获取某个被public修饰的构造方法Constructor con=clazz.getConstructor(String.class);System.out.println(con);//2.4 getDeclaredConstructor获取指定的某个构造方法Constructor<Person> con1=clazz.getDeclaredConstructor(String.class,int.class);System.out.println(con1);//3.解剖//包-0 public-1 private-2 protected-4int modifier=con1.getModifiers();System.out.println(modifier);System.out.println("权限修饰符是否是公共的:"+ Modifier.isPublic(modifier));//获取方法的形参Parameter[] pars=con1.getParameters();for(Parameter par:pars){System.out.println(par.getType()+"-"+par.getName());}//4.实例化对象con1.setAccessible(true);//临时取消权限校验符Person per=con1.newInstance("张三",12);System.out.println(per);}
}
import java.lang.reflect.Field;public class Demo05 {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {//1.获取类的字节码文件对象Class clazz = Dog.class;//2.获取成员变量//getFields()获取类中所有public修饰的成员变量(包括父类)
// Field[] fields=clazz.getFields();
// for(Field field:fields){
// System.out.println(field);
// }//getDeclaredFields()获取到本类中的所有的成员变量
// Field[] fields=clazz.getDeclaredFields();
// for(Field field:fields){
// System.out.println(field);
// }//getField()获取本类或父类中某个被public修饰的成员变量
// Field field=clazz.getField("type");
// System.out.println(field);//getDeclaredField获取到本类中某个成员变量Field field = clazz.getDeclaredField("color");System.out.println(field);//3.解剖//获取权限修饰符int modifiers = field.getModifiers();System.out.println("权限修饰符为:" + modifiers);//获取数据类型Class typeClass = field.getType();System.out.println("数据类型为:" + typeClass);//获取变量名String name = field.getName();System.out.println("此成员变量对象的变量名为:" + name);//4.应用Dog d2 = new Dog();Dog d1 = new Dog("小花", 1, "田园犬", 10.5, 20, "白色");
// field.setAccessible(true);//临时取消权限修饰符//获取对象d1中此成员变量的值
// Object obj = field.get(d1);
// System.out.println("获取到成员变量type对应对象的值为:" + obj);//设置对象d1中此成员变量的值为黑白
// field.set(d1, "黑白");
// System.out.println(d1);//静态成员变量不依赖于对象field.setAccessible(true);//获取静态成员变量,不依赖于对象而存在,所以获取此成员变量的值时,可以不传对象Object obj = field.get(null);System.out.println("获取静态成员变量color对应的值为:" + obj);//设置成员变量值,静态成员变量共享一片空间,所以可以修改field.set(null, "黑白");System.out.println(d1);System.out.println(d2);}
}class Animal {public String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}
}class Dog extends Animal {public String type;protected double weight;int height;private static String color;@Overridepublic String toString() {return "Dog{" +"type='" + type + '\'' +", weight=" + weight +", height=" + height +", color='" + color + '\'' +'}';}public Dog() {}public Dog(String name, int age, String type, double weight, int height, String color) {super(name, age);this.type = type;this.weight = weight;this.height = height;this.color = color;}
}
案例:
public class Demo06 {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {ArrayList<Integer> list = new ArrayList<>();//获取list的成员变量elementData看长度Class clazz=list.getClass();Field field = clazz.getDeclaredField("elementData");field.setAccessible(true);Object[] obj=(Object[]) field.get(list);System.out.println(obj.length);// list.add("123");//获取list的成员变量elementData看长度// for (int i = 0; i < 20; i++) {
// list.add(String.valueOf(i));
// obj=(Object[]) field.get(list);
// System.out.println("数组的长度为:"+obj.length+"元素个数"+list.size());
// }//获取list的成员变量elementData看长度list.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9,0,11));obj=(Object[]) field.get(list);System.out.println("数组的长度为:"+obj.length+"元素个数"+list.size());}
}
获取普通方法:
import java.lang.reflect.Method;public class Demo01 {public static void main(String[] args) throws NoSuchMethodException {//1.获取student类的字节码文件对象Class clazz = Student.class;//2.获取方法//getMethods获取本类和父类中所有被public修饰的方法
// Method[] methods=clazz.getMethods();
// for(Method method:methods){
// System.out.println(method);
// }//getDeclaredMethods获取本类中所有声明的方法
// Method[] methods1=clazz.getDeclaredMethods();
// for(Method method:methods1){
// System.out.println(method);
// }//getMethod,通过方法名和参数项获取本类或父类中某个被public修饰的方法
// Method method=clazz.getMethod("eat",String.class);
// System.out.println(method);//getDeclaredMethod,通过方法名和参数项获取本类中某个声明的方法Method method1 = clazz.getDeclaredMethod("eat", String.class);System.out.println(method1);}
}
public class Demo02 {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {//1.获取student类的字节码文件对象Class clazz = Student.class;//2.getDeclaredMethod,通过方法名和参数项获取本类中某个声明的方法Method method = clazz.getDeclaredMethod("eat", String.class, int.class);//3.解剖//3.1 获取权限修饰符int number = method.getModifiers();System.out.println("权限修饰符为:" + number);//3.2 返回值类型Class returnType = method.getReturnType();System.out.println("返回值类型:" + returnType);//3.3方法名String methodName = method.getName();System.out.println("方法名为:" + methodName);//3.4参数项Parameter[] parameters = method.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter.getType() + "-" + parameter.getName());}//3.5异常信息Class[] classes = method.getExceptionTypes();for (int i = 0; i < classes.length; i++) {System.out.println("第" + (i + 1) + "个异常信息为:" + classes[i]);}//4.普通方法的调用//invoke(obj--对象,args--参数值)
// Student s1=new Student();
// s1.name="rosie";
// method.setAccessible(true);//有返回值的方法调用
// Object obj=method.invoke(s1,"小蛋糕",2);
// System.out.println(obj);//5.静态方法的调用(不依赖于对象)Method method1 = Student.class.getDeclaredMethod("getUUID");Object uuid=method1.invoke(null);//静态方法,可以不传入对象System.out.println(uuid);}
}
import java.util.UUID;public class Student extends Person{private String name;private int age;private char gender;private double height;private String hobby;public Student() {}public Student(String name, int age, char gender, double height, String hobby) {super();this.name = name;this.age = age;this.gender = gender;this.height = height;this.hobby = hobby;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", gender=" + gender +", height=" + height +", hobby='" + hobby + '\'' +'}';}private void eat(){System.out.println("他喜欢吃垃圾食品");}private String eat(String sth,int number) throws ClassCastException,IllegalAccessException,NullPointerException{return name+"喜欢吃"+sth+"每天"+number+"次";}protected static UUID getUUID(){return UUID.randomUUID();}void test(){System.out.println("这个是测试方法");}@Overridepublic void hello(){System.out.println("Student:hello");}
}
继承关系:Student继承自Person.
public class Person {public void hello(){System.out.println("Person:hello");}
}
public class Demo03 {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {//1.获取Hello方法Method m1=Person.class.getMethod("hello");//对Person实例调用hello方法
// Person p1=new Person();
// m1.invoke(p1);//对Student实例调用hello方法Person p2=new Student();m1.invoke(p2);}
}
案例:
public class Teacher {private String name;private String subject;public void teach() {System.out.println("teach java");}public Teacher() {super();}public Teacher(String name, String subject) {super();this.name = name;this.subject = subject;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSubject() {return subject;}public void setSubject(String subject) {this.subject = subject;}@Overridepublic String toString() {return "Teacher [name=" + name + ", subject=" + subject + "]";}
}
//对于获取到的任意一个对象,请将对象中的所有的字段
public class Demo04 {public static void main(String[] args) throws IOException, IllegalAccessException {Student s1=new Student("rosie",20,'女',172,"唱跳");Teacher t1=new Teacher("彭王子","数据库");showMessage(t1);}//对于获取到的任意一个对象,请将对象中的所有字段和值保存到本地文件中,每个字段与其对应的值占用一行public static void showMessage(Object obj) throws IOException, IllegalAccessException {OutputStream os=new FileOutputStream("E:\\YuanJiuYuan\\IoTest\\a.txt");//请将对象中的所有字段和值保存到本地文件中,每个字段与其对应的值占用一行Class clazz=obj.getClass();Field[] fields=clazz.getDeclaredFields();for(Field field:fields){String name=field.getName();field.setAccessible(true);Object value=field.get(obj);os.write((name+"="+value+"\r\n").getBytes());}}
}
下面这段代码演示了Java反射机制的使用,通过读取配置文件动态加载类并调用指定方法,实现了程序的灵活性和可配置性。
public class Demo05 {public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {InputStream is=Demo05.class.getResourceAsStream("/prop.properties");Properties p1=new Properties();p1.load(is);System.out.println(p1.getProperty("classname"));System.out.println(p1.getProperty("method"));Class classname = Class.forName(p1.getProperty("classname"));Method method= Class.forName(p1.getProperty("classname")).getDeclaredMethod(p1.getProperty("method"));Object obj = classname.newInstance();method.invoke(obj);}
}