Callable
定义:public interface Callable
JDK1.5之后出现,与Runnable接口类似,实现之后代表一个线程任务
Callable具有泛型返回值,可以声明异常
方法:public V call() throws Exception
相当于Runnable接口中的run()方法,但是有返回值
如何开启start方法:
1)FutureTask类继承自Runnable,并有构造参数可以接收Callable接口的实现类对象,在通过Thread接收Runnable实现类对象的构造方法,启动start()。
FutureTask同时继承Future方法,继承的get()方法可以获得Callable的call()方法的返回值。
2)通过线程池提交线程任务来实现Callable多线程
public class CallableDemo {
public static void main(String[] args) throws Exception {
//1、创建Callable对象
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "开始计算");
int sum = 0;
for(int i = 0 ; i < 100 ; i++) {
sum+= i ;
}
return sum;
}
};
//把callable对象转成可执行的任务
FutureTask<Integer> ft = new FutureTask<Integer>(callable);
//Thread
new Thread(ft).start();
//接收返回值FutureTask.get(),等待call方法执行完毕,才会返回
Integer sum = ft.get();
System.out.println(sum);
}
}
线程池
定义:线程池可以理解为是一个线程容器,可设定线程分配的数量上限。
作用:将预先创建的线程对象存入池中,并重用线程池中的线程对象,避免频繁的创建和销毁线程,占用资源。
常用的线程池接口和类
都在java.util.concurrent包中
1)Executor:线程池的顶级接口
定义:public interface Executor
方法:public void execute(Runnable command)
2)ExecutorService:线程池接口
定义:public interface ExecutorService extends Executor
方法:public Future<?> submit(Runnable task)
public Future submit(Callable task)
//提交线程任务
3)Executors线程池工厂类(通过此类可以获得一个线程池)
定义:public class Executors extends Object
方法:
创建固定数量的线程池:public static ExecutorService newFixedThreadPool(int nThreads)//参数为线程池中的线程数量
获得动态数量的线程池:public static ExecutorService newCachedThreadPool()
创建单线程池:public static ExecutorService newSingleThreadExecutor()
创建调度线程池:public static ExecutorService newScheduledThreadPool(int corePoolSize)
public class ThreadPool {
public static void main(String[] args) {
//1、创建固定线程个数的线程池
//ExecutorService es = Executors.newFixedThreadPool(4);
//2、创建缓存线程池:线程个数由提交的任务决定
ExecutorService es = Executors.newCachedThreadPool();
//3、创建单线程池:里面只有一个线程
//ExecutorService es = Executors.newSingleThreadExecutor();
//4、创建调度线程池,调度:周期,定时执行
//ExecutorService es = Executors.newScheduledThreadPool(4);
//创建任务
Runnable runnable = new Runnable() {
private int ticket = 100;
@Override
public void run() {
while(true) {
if(ticket <= 0) {
break;
}
System.out.println(Thread.currentThread().getName() + "第" + ticket-- + "票");
}
}
};
//提交任务
for(int i = 0 ; i < 5 ; i++) {
Future<?> ft = es.submit(runnable);
System.out.println(ft);
}
//关闭线程池
es.shutdown();//等待任务执行完毕
es.shutdownNow();//立即关闭不等待任务完成
}
}
ExecutorService提交线程任务的方法的返回值为Future<?>,Future接口具有get()方法,可以获取线程的返回值,返回值可以通过Callable接口的call方法实现。
方法:public Future submit(Callable task)
//使用两个线程,并发计算1-50,51-100的和,在进行汇总
public class FutureDemo {
public static void main(String[] args) throws Exception{
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Integer> result1 = es.submit(new Callable<Integer>(){
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "开始计算1-50");
int sum = 0;
for(int i = 1 ; i <= 50 ; i++) {
sum += i;
}
return sum;
}
});
Future<Integer> result2 = es.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "开始计算51-100");
int sum = 0;
for(int i = 51 ; i <= 100 ; i++) {
sum += i;
}
return sum;
}
});
int res = result1.get() + result2.get();
System.out.printf("结果为%d + %d = %d", result1.get(), result2.get(), res);
es.shutdown();
}
}
/*运行结果
pool-1-thread-1开始计算1-50
pool-1-thread-2开始计算51-100
结果为1275 + 3775 = 5050
*/
注解(Annotation)
从jdk1.5开始,不是程序本身,可以对程序作出解释,可以被其他程序(编译器等)读取。
格式
注解以@注释名在代码中存在,还可以添加一些参数值
使用
可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息
内置注解
@Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法生命打算重写超类中的另一个方法声明
@Deprecated:定义在java.lang.Deprecated中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择
@SuppressWarnings:定义在java.lang.SuppressWamings中,用来抑制编译时的警告信息
与前两个不同,需要添加参数
@SuppressWarnings(“all”)
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”,“deprecation”})等
元注解
作用是负责注解其他注解,java定义了4个校准的meta-annotation类型,他们被用来提供对其他annotation类型做说明
这些类型和它们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inhrited)
@Target:用于描述注解的适用范围(即注解可以用在什么地方)
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME)
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
1)@interface用来声明一个注解,public @interface 注解名{自定义内容}
2)其中的每一个方法实际上是声明了一个配置参数
3)方法的名称就是参数的名称
4)返回值类型就是参数的类型(返回值只能是基本类型Class,String,enum)
5)可以用过default来声明参数的默认值
6)如果只有一个参数成员,一般参数名value
7)注解元素必须要有值,我们定义注解元素时,经常使用空字符串0作为默认值
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
//注解的参数:参数类型 + 参数名();
String name() default "";
int age () default 0;
int id() default -1;//如果默认值为-1,代表不存在
String[] schools();
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//只有一个参数最好写value
String value();
}
public class AnnatationDemo {
//注解可以显示赋值,如果没有默认值则必须给注解赋值
@MyAnnotation(name = "秦酱",schools = {"西北大学"})
public void test() {};
//只有一个值,且参数名为value,可以省略参数名 =
@MyAnnotation2("X")
public void test2() {};
}