构造方法----------------------------------------------------------
newCachedThreadPool(): 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
newFixedThreadPool(int nThreads): 创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。
newScheduledThreadPool(int corePoolSize): 创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
newSingleThreadExecutor(): 创建一个使用从无界队列运行的单个工作线程的执行程序。
构造方法----------------------------------------------------------
线程池执行任务的API:
1.submit(Runnable/Callable)
2.execute(Runnable)
代码实现:newCachedThreadPool()
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Pool {
public static void main(String[] args) {
//通过匿名内部类创建任务类对象
Runnable task = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
};
//创建线程池,包涵线程数为3
ExecutorService pool = Executors.newFixedThreadPool(3);
//提交任务类对象给线程池中的线程对象
//线程池自动依序分配线程并开启线程
//如果提交线程数大于线程池线程数,线程池会依次将最先运行结束的线程对象分配给超出任务类对象
//即超出的任务类必须等待线程池中的线程运行完毕
pool.submit(task);
pool.submit(task);
pool.submit(task);
pool.submit(task);
//线程运行完毕,主线程结束,但线程池不会结束
//用shutdown方法关闭线程池,程序才会结束
pool.shutdown();
}
}
线程池的好处? 为什么使用线程池?
见我的收藏 - 线程池原理
Callable(线程任务, 只能用在线程池) -> Runnable
new Thread(new Runnable(){});
new Thread(new Callable(){}); // — 错误的!!
Callable对象只能在 : Future f = pool.submit(Callable);
f.get() -> 得到call方法的返回值
可能会遇到阻塞
f.get(long, TimeUnit.xx) -> 超时继续
代码实现:
import java.util.Date;
import java.util.concurrent.*;
public class CallableDemo {
public static void main(String[] args) {
//创建Callable类,专门给线程池使用,无法在线程构造方法中使用
Callable<Date> callable = new Callable<Date>() {
//重写call方法,call方法有返回值,返回值类型与对象泛型相同
@Override
public Date call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
//延时10秒
Thread.sleep(10000);
//返回当前时间
return new Date();
}
};
//创建单个线程池
ExecutorService single = Executors.newSingleThreadExecutor();
//提交callable任务类对象,submit方法有返回值,返回值类型为future,泛型需要设置与callable返回值类型相同,未设置默认为Object
Future<Date> f = single.submit(callable);
/*try {
//调用该future对象的get方法获得callable的返回值
//因为callable的run方法中延时了10秒才返回结果,方法才结束,所以会对主方法线程产生阻塞效果
Date date = f.get();
//必须等待callable线程运行完成
System.out.println(date);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}*/
try {
Date date = f.get(3, TimeUnit.SECONDS);//get方法等待三秒,如果3秒还没有返回结果,get方法结束(超时结束)
System.out.println(date);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
System.out.println("get方法超时");
}
//关闭线程池
single.shutdown();
}
}
Lambda表达式: JDK1.8 函数式编程思想
面向对象思想: 什么对象, 做什么, 结果是什么
函数式编程思想: 强调做什么,而不是以什么形式做。
语法: (参数列表) -> {一些代码}
使用Lambda前提:
1.实现一个接口
2.接口中只有一个抽象方法
3.接口对象是作为方法参数使用的
(参数列表) -> {一些代码}
(参数列表): 表示要重写的抽象方法的参数列表
-> : 固定语法, 指向/传递的意思
{一些代码}: 要重写的方法体
Lambda 取代匿名内部类的
匿名内部类: 本质还是类, 编译后也会生成字节码文件, 运行时也要加载
Lambda: 本质是一个函数, 编译后不会有字节码文件, 直接从内存中获取
效率更高
可推导即可省略:
1.() 中的参数类型, 可以省略, 如果有多个参数, 每个参数类型都要一起省略
2.{} 中如果只有一行代码, 不论这个方法有没有返回值, 那么[{} return ;] 可以省略
{} return ; 必须一起省略
3.() 中如果只有一个参数, () 可以省略, 和类型一起省略
() 中如果没有参数, 必须写 ()
代码实现:
创建函数式接口
//注解:函数式接口检测(接口中只有一个抽象方法)
@FunctionalInterface
public interface MyInterface {
int echo(String s);
}
接口作为参数的Lambda表达式简化
import java.util.*;
public class LambdaDemo {
//注解,属于程序的一部分,编译器可识别
@SuppressWarnings("all")//压制全部警告
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("普通任务方法");
}
});
//lambda表达式只能在参数列表里使用,且被简化的参数必须只有一个抽象方法
//lambda表达式优化
Thread thread1 = new Thread(() -> System.out.println("lambda表达式任务方法"));
thread1.start();
//创建列表
List<String> list = List.of("lucy", "hzt", "ana", "alice");//List.of方法返回的是一个内部类,并不是真正列表
ArrayList<String> arrayList = new ArrayList<>(list);
Collections.sort(arrayList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});//传入一个比较器对象,根据长度排序
//使用lambda简化
Collections.sort(arrayList, ( o1, o2) -> o1.length() - o2.length());
System.out.println(arrayList);
//调用将接口作为参数的方法,使用匿名内部类实现接口对象的抽象方法以创建接口对象
method(new MyInterface() {
@Override
public int echo(String s) {
return s.length();
}
}, "HelloWorld");
//使用lambda进行简化
//1.首先此方法调用了接口对象作为参数,且此接口对象只有一个必须实现的抽象方法,所以接口匿名内部类的 new 构造方法名(){} 重写方法名都可以省略
// 用->连接(接口参数列表) -> {代码块}
int s0 = method((String s) -> {
return s.length();}, "HelloWorl");
//2.调用接口的匿名内部类的参数列表中的参数类型也可以省略,多个参数的参数类型必须同时省略
method((s) -> {
return s.length();}, "HelloWorld");
//3.如果调用接口的匿名内部类的参数列表中的参数只有一个,那么参数列表的()也可以省略,但是必须和列表中参数类型同时省略
method(s -> {
return s.length();}, "HelloWorld");
//4.如果调用接口的匿名内部类中重写的抽象方法只有一句代码,那么 代码块的{} return ; 都可以省略且必须一起省略
int s1 = method(s -> s.length(), "HelloWorld");//用来接收方法返回值的变量名不能与函数表达式参数相同
System.out.println(s0 + " " + s1);
}
//创建一个用接口作为参数的方法
public static int method(MyInterface inf, String s){
return inf.echo(s);
}
}
函数式接口: 接口中只有一个抽象方法, 默认方法\静态方法\私有方法 随意
@FunctionalInterface -> 注解
注解: JDK 1.5 属于程序的一部分, 可以取代一部分配置信息
@Override -> 检测方法是不是重写
@SuppressWarnings -> 压制警告
@Deprecated -> 标记一个类或者方法或者变量, 过时的
@FunctionalInterface -> 检测一个接口是不是函数式接口
JUnit: 单元测试 -> 以方法为单位, 可以取代主方法
System.out.println(); -> 打桩测试
Debug -> 断点测试
JUnit -> 单元测试
别人写好的代码, 我们想要使用
1.将别人写好的代码工程, 打包 jar 文件
是将编译后的字节码文件打包的
2.在自己的工程中 关联这个jar文件 -> 添加依赖
3.代码中直接使用 import
JUnit使用步骤:
1.在工程中创建一个文件夹lib
2.将2个jar包复制到lib中
3.选择jar包 右键 -> Add as Library… 默认添加即可
4.写一个测试类, 在其中写一个方法[不需要返回值,不需要参数]
5.在方法上添加注解 @Test
6.运行这个方法即可
JUnit常用注解:
@Test: 测试的方法, 可以直接运行
@Before: 在测试方法之前调用的
@After: 在测试方法之后调用的
可变长参数:
取代了数组 int[] arr -> int… arr
JDK1.5后, 修改为可变长参数
1.方法中, 除了可变长参数, 还有别的参数, 可变长参数必须放在参数列表最后
2.而且一个方法中, 只能有一个可变长参数
代码实现:
import org.junit.Before;
import org.junit.Test;
public class tes {
// @Test//单元测试方法必须是无参的
public static void variableArity(String s, int... a){
for(int i: a){
System.out.println(i);
}
System.out.println(s);
}
@Before
public void func1(){
System.out.println("before注解方法在所有test注解方法之前运行");
}
@Test //单元测试方法可以直接运行,不需要主方法调用
public void func2(){
System.out.println("测试方法2");
}
@Test
public void func3(){
System.out.println("测试方法3");
}
@Test
public void func4(){
System.out.println("测试方法4");
}
public static void main(String[] args) {
//可变长参数方法
variableArity("可变长参数方法", 0);//可变长参数必须放在参数列表最后一个,且只有一个
variableArity("可变长参数方法", 0, 1);
variableArity("可变长参数方法", 0, 1, 2);
variableArity("可变长参数方法", 0, 1, 2, 3);
}
}