什么是线程池。
线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,
省去了频繁创建和销毁线程对象的操作,无需反复创建线程而消耗过多资源。
为什么要用线程池:
合理利用线程池能够带来三个好处
1.降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.提高响应速度
3.提高线程的可管理性
线程池的核心思想:线程复用。同一个线程可以被重复使用。
线程池的创建方式一
线程池在Java中的代表: ExecutorService
创建线程池的API:
java.util.concurrent.Executors类下:
– public static ExecutorService newFixedThreadPool(int nThreads)`:
返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最大数量)
往线程池ExecutorService中创建线程的API:
1.public Future<?> submit(Runnable task)
2. Future submit(Callable task);
线程池启动后是不会死亡的,因为后续还要重复使用的。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo1 {
public static void main(String[] args) {
//创建一个线程池
ExecutorService pools = Executors.newFixedThreadPool(3);
Runnable target = new MyRunnable();
//加线程执行就好
pools.submit(target);
pools.submit(target);
pools.submit(target);
//重复调用上面一个线程
pools.submit(target);
//等线程执行完后关闭线程
pools.shutdown();
// 立即关闭线程,不管是不是执行完了
// pools.shutdown();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"=>"+i);
}
}
}
线程池的创建方式二
线程池在Java中的代表: ExecutorService
创建线程池的API:
java.util.concurrent.Executors类下:
public static ExecutorService newFixedThreadPool(int nThreads)`:返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最大数量)
往线程池中创建线程的API:
1.public Future<?> submit(Runnable task)
2. Future submit(Callable task);
public class ThreadPools {
public static void main(String[] args) throws Exception {
// 1.新建一个只能存储3个线程的线程池。
ExecutorService pools = Executors.newFixedThreadPool(3);
Future<Integer> task1 = pools.submit(new MyCallable(5));
Future<Integer> task2 = pools.submit(new MyCallable(10));
Future<Integer> task3 = pools.submit(new MyCallable(15));
Future<Integer> task4 = pools.submit(new MyCallable(20));
System.out.println(task1.get());
System.out.println(task2.get());
int rs = task3.get();
System.out.println(rs);
System.out.println(task4.get());
}
}
class MyCallable implements Callable<Integer>{
private int n ;
public MyCallable(int n){
this.n = n;
}
@Override
public Integer call() throws Exception {
int count = 0 ;
for(int i = 1; i <= n ; i++ ){
count+=i;
System.out.println(Thread.currentThread().getName() + ":开始累加"+i);
}
return count;
}
public int getN() {
return n;
}
public void setN(int n) {
this.n = n;
}
}
Stream流
什么是Stream流?
在Java 8中,得益于Lambda所带来的函数式编程,
引入了一个全新的Stream流概念,用于解决已有集合/数组类库既有的弊端。
Stream流能解决什么问题?
可以解决已有集合类库或者数组API的弊端。
Stream流可以简化集合的操作,Stream流提供了强大的元素筛选机制。
代码可读性更好,更加优雅!
##Stream流的获取
流式思想的核心:是先得到集合或者数组的Stream流(就是一根传送带)
然后就在这个Stream流操作集合或者数组的元素。
Stream流简化替代集合操作的API.
集合获取流的API:
(1) default Stream<E> stream();
*/
public class StreamDemo01 {
public static void main(String[] args) {
/** --------------------Collection集合获取流------------------------------- */
// Collection集合如何获取Stream流。
Collection<String> lists = new ArrayList<>();
Stream<String> ss = lists.stream();
/** --------------------Map集合获取流------------------------------- */
Map<String, Integer> map = new HashMap<>();
// 先获取键的Stream流。
Stream<String> keyss = map.keySet().stream();
// 在获取值的Stream流
Stream<Integer> valuess = map.values().stream();
// 获取键值对的Stream流(key=value: Map.Entry<String,Integer>)
// key=value , key = value
Stream<Map.Entry<String,Integer>> keyAndValues = map.entrySet().stream();
/** ---------------------数组获取流------------------------------ */
// 数组也有Stream流。
String[] arrs = new String[]{"Java", "JavaEE" ,"Spring Boot"};
Stream<String> arrsSS1 = Arrays.stream(arrs);
Stream<String> arrsSS2 = Stream.of(arrs);
}
}
Stream流的常用方法。
流式编程的核心思想:是把集合或者数组转成Stream流,然后
通过调用流的方法,完成各种功能操作。
Stream流的方法:
forEach , count, filter , limit , skip , map 把传送带上的每个元素进行加工再放上去 concat:连接流。
终结与非终结方法
终结方法一旦调用就没有Stream流返回了,操作就结束了。(传送带的使命就结束了!)
非终结方法是每次调用都会返回一个新的Stream流,程序员就可以继续操作。
常见终结方法:foreach count
public class StreamDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("周伯通");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
// forEach 遍历
list.stream().filter(s-> s.startsWith("周")).forEach(System.out::println);
// count统计个数
long count = list.stream().filter(s-> s.startsWith("周")).count();
System.out.println(count);
// limit 只要前2个元素
list.stream().filter(s -> s.length() == 3).limit(2).forEach(System.out::println);
// skip 跳过前2个
list.stream().filter(s -> s.length() == 3).skip(2).forEach(System.out::println);
}
}
收集Stream流。
Stream流的作用是为了帮助操作集合,操作完的数据依然是在Stream流上。
但是实际开发的时候,数据最终的形式还应该是集合或者数组。
开发中:集合 -> 通过Stream流辅助操作它 -> 转回成集合(收集Stream流)。
小结:
流像水一样,只能用一次,
一个Stream流只能用一次!!!
public class StreamDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("周伯通");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
// forEach 遍历
Stream<String> ss = list.stream().filter(s -> s.startsWith("张") && s.length()==3);
// 收集Stream流成为一个集合: 面向对象的思想设计的。
List<String> names1 = ss.collect(Collectors.toList());
System.out.println(names1);
Stream<String> ss1 = list.stream().filter(s -> s.startsWith("张") && s.length()==3);
Set<String> names2 = ss1.collect(Collectors.toSet());
System.out.println(names2);
// 把流收集成数组
Stream<String> ss2 = list.stream().filter(s -> s.startsWith("张") && s.length()==3);
Object[] objs = ss2.toArray();
System.out.println(Arrays.toString(objs));
// 收集成特定类型的数组!!
Stream<String> ss3 = list.stream().filter(s -> s.startsWith("张") && s.length()==3);
String[] objs1 = ss3.toArray(String[]::new);
System.out.println(Arrays.toString(objs1));
}
}