需求:
当主线程要处理多个不同的耗时任务时,又不想阻塞线程等待每个任务的完成后才能继续走下去,可以将部分耗时任务交给子线程处理,到时候在查看结果,自己则继续往下面执行,等到自己处理完自己的任务后,在来检查子线程是否完成自己分发的任务。可以等待线程完成任务在执行其他任务。
注意:由于Java语言没有指针对象,无法操作地址,当返回类型为值类型等非引用对象类,无法将结果成功的返回,此方法只适合返回结果引用对象的方法(哪位大神能够弄成C语言类,并完善,可以试试)
实现步骤:
1.新建一个AsyncProxyMethod的Java类
package com.moodincode.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
/**
* Created by moodInCode on 2018/5/25.
* 方法异步执行代理类
*/
public class AsyncProxyMethod {
private Method method;//方法
private static Semaphore semaphore = new Semaphore(1);//定义信号量
private Boolean isSuccess=false;//方法是否成功执行
/**
* 构造函数实例化method对象
* @param instanceClass //化需要调用的方法的类的实例化对象
* @param methodName//需要调用的方法的方法名
* @param parameterTypes//方法的参数类型
* @throws NoSuchMethodException
*/
public AsyncProxyMethod(Object instanceClass, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
this.method = instanceClass.getClass().getMethod(methodName,parameterTypes);
}
/**
* 执行方法
* @param instanceClass//静态方法,此处传值为null,非静态方法需要传入方法所属类的实例化对象
* @param result//需要接受返回值的引用对象
* @param params//方法体所需的传参值
*/
public void invoke( Object instanceClass,Object result, Object... params){
//开辟线程异步处理耗时方法
Thread thead=new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();//获取信号量
Object object= method.invoke(instanceClass, params);
//拷贝返回结果到引用对象中
copyByName(object,result);
isSuccess=true;//标识方法成功执行
semaphore.release();//释放信号量
} catch (Exception e) {
semaphore.release();
e.printStackTrace();
}
}
});
thead.start();
}
/**
* 等待线程完成
* 判断使用的方法是否执行完毕,阻塞等待信号量的释放
*/
public void waitForFinish(){
try {
semaphore.acquire();
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
/**
* 判断是否已完成任务
* @return
*/
public boolean isFinish(){
Boolean bool=false;
if(semaphore.tryAcquire()){
bool=true;
semaphore.release();
}
return bool;
}
/**
* 判断是否成功执行方法
* @return
*/
public boolean isSuccess(){
return this.isSuccess;
}
/**
* 属性配置
* @param src 需要拷贝的对象源
* @param target 输出的目标对象
*/
public static void copyByName(Object src, Object target) {
if (src == null || target == null) {
return;
}
try {
Map<String, Field> srcFieldMap= getAssignableFieldsMap(src);
Map<String, Field> targetFieldMap = getAssignableFieldsMap(target);
if(srcFieldMap.size()<1){
target= src;
}
for (String srcFieldName : srcFieldMap.keySet()) {
Field srcField = srcFieldMap.get(srcFieldName);
if (srcField == null) {
continue;
}
// 变量名需要相同
if (!targetFieldMap.keySet().contains(srcFieldName)) {
continue;
}
Field targetField = targetFieldMap.get(srcFieldName);
if (targetField == null) {
continue;
}
// 类型需要相同
if (!srcField.getType().equals(targetField.getType())) {
continue;
}
targetField.set(target,srcField.get(src));
}
}catch (Exception e) {
// 异常
}
return ;
}
/**
* 获取对象中需要拷贝的字段
* @param obj
* @return
*/
private static Map<String, Field> getAssignableFieldsMap(Object obj) {
if (obj == null) {
return new HashMap<String, Field>();
}
Map<String, Field> fieldMap = new HashMap<String, Field>();
for (Field field : obj.getClass().getDeclaredFields()) {
// 过滤不需要拷贝的属性
if (Modifier.isStatic(field.getModifiers())
|| Modifier.isFinal(field.getModifiers())) {
continue;
}
field.setAccessible(true);
fieldMap.put(field.getName(), field);
}
return fieldMap;
}
}
2.测试调用例子
2.1新建一个Student.java类
package com.moodincode.test;
/**
* Created by moodInCode on 2018/5/25.
*/
public class Student{
String name;
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.2新建一个方法类和main()方法中调用,本例子将方法和调用mian方法都写在Test2.Java的类中
package com.moodincode.test;
import java.util.Random;
/**
* Created by moodInCode on 2018/5/23.
*/
public class Test2 {
public Test2(String ee) {
}
public static void main(String[] args){
Student stu1=new Student();//传入对象(方法中需要的参数值)
Student stu2=new Student();//传入对象(方法中需要的参数值)
Student stu3=new Student();//传入对象(方法中需要的参数值)
Student stu4=new Student();//接受结果对象
Student stu5=new Student();//接受结果对象
Student stu6=new Student();//接受结果对象
try {
//模拟三个耗时的方法
AsyncProxyMethod p1= new AsyncProxyMethod(new Test2("ee"),"getStudent",Student.class);//构造函数,初始化method对象
p1.invoke(null,stu4,stu1);//调用代理线程执行方法
AsyncProxyMethod p2= new AsyncProxyMethod(new Test2("ee"),"getStudent",Student.class);//构造函数,初始化method对象
p2.invoke(null,stu5,stu2);//调用代理线程执行方法
AsyncProxyMethod p3= new AsyncProxyMethod(new Test2("ee"),"getStudent",Student.class);//构造函数,初始化method对象
p3.invoke(null,stu6,stu3);//调用代理线程执行方法
System.out.println("====方法执行完成前======");
System.out.println("参数对象1,用户姓名:"+stu1.getName()+"年龄:"+stu1.getAge());
System.out.println("参数对象2,用户姓名:"+stu2.getName()+"年龄:"+stu2.getAge());
System.out.println("参数对象3,用户姓名:"+stu3.getName()+"年龄:"+stu3.getAge());
System.out.println("接受结果对象4,用户姓名:"+stu4.getName()+"年龄:"+stu4.getAge());
System.out.println("接受结果对象5,用户姓名:"+stu5.getName()+"年龄:"+stu5.getAge());
System.out.println("接受结果对象6,用户姓名:"+stu6.getName()+"年龄:"+stu6.getAge());
System.out.println("代理P1是否执行完毕"+p1.isFinish());
System.out.println("代理P1是否成功执行:"+p1.isSuccess());
System.out.println("方法系统当前时间为:"+p1.isSuccess());
p1.waitForFinish();//等待异步代理完成,阻塞下面语句
p2.waitForFinish();//等待异步代理完成,阻塞下面语句
p3.waitForFinish();//等待异步代理完成,阻塞下面语句
System.out.println("====异步代理执行完成后======");
System.out.println("参数对象1,用户姓名:"+stu1.getName()+"年龄:"+stu1.getAge());
System.out.println("参数对象2,用户姓名:"+stu2.getName()+"年龄:"+stu2.getAge());
System.out.println("参数对象3,用户姓名:"+stu3.getName()+"年龄:"+stu3.getAge());
System.out.println("接受结果对象4,用户姓名:"+stu4.getName()+"年龄:"+stu4.getAge());
System.out.println("接受结果对象5,用户姓名:"+stu5.getName()+"年龄:"+stu5.getAge());
System.out.println("接受结果对象6,用户姓名:"+stu6.getName()+"年龄:"+stu6.getAge());
System.out.println("代理P1是否执行完毕"+p1.isFinish());
System.out.println("代理P1是否成功执行:"+p1.isSuccess());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* 获取学生信息的方法,作为异步代理的方法
* @param stu
* @return
*/
public static Student getStudent(Student stu){
try {
Thread.sleep(1300);//让程序休眠一段时间,模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
Random r1 = new Random();
Integer i=r1.nextInt(100);
stu.setAge(i);
stu.setName("机器人:"+i);
return stu;
}
}
2.3执行结果打印如下所示: