一.创建线程的3种方式
- 继承Thread类重写run方法,实际上实现了Runable接口
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
new Thread() {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println("i="+i);
}
}
}.start();
}
}
- 定义实现Runnable接口的类并重写run方法
public class Main {
public static void main(String[] args) {
new Thread(()->{
for (int i = 0; i <100 ; i++) {
System.out.println("i="+i);
}
});
}
}
- 实现Callable接口创建futureTask(实现了Runnable)对象,通过get获得结果
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask=new FutureTask<>( ()->{
int sum=0;
for (int i = 0; i <100 ; i++) {
sum+=i;
}
return sum;
});
new Thread(futureTask).start();
System.out.println(futureTask.get());//获取futureTask结果
}
}
二.线程的基本操作
- 线程的一些基本属性设置和获取
public class Main {
public static void main(String[] args){
Thread.currentThread();//得到当前线程
Thread.activeCount();//获得活跃的线程数量
//Thread.State 顶一个线程各种状态常量
Thread thread=new Thread();
thread.getName();//获取线程名字
thread.getId();//获取线程ID
thread.setPriority(Thread.NORM_PRIORITY);
//设置线程优先级,优先级高的获得cpu执行权概率越高,高优先级的需要定时的调用yield和slepp等方法,给其他第优先级线程机会。
thread.setDaemon(true);//设置线程位守护线程,守护线程是为其他线程做辅助工作,不能单独运行,其他所有线程结束,他就结束
}
}
- 线程的时间调度
- Theard.sleep(long time);
①sleep()释放CPU执行权,但不释放同步锁;
②wait()释放CPU执行权,也释放同步锁,使得其他线程可以使用同步控制块或者方法。
这是两个的关键区别
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000);//当前所在线程进入1000毫秒timeWatiing状态,时间结束后进入就绪状态
}
}
- thread.join();
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println("i="+i);
}
});
Thread thread1=new Thread(()->{
for (int i = 0; i < 100; i++) {
if(i==2){
try {
thread.join(1);
//表示让thread先执行1毫秒,然后在一起竞争cpu执行权
//如果为0表示一直等待,直到结束,进入就绪
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("j="+i);
}
});
thread.start();
thread1.start();
}
}
- thread.yield()
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println("i="+i);
}
});
Thread thread1=new Thread(()->{
for (int i = 0; i < 100; i++) {
if(i==2){
thread.yield();
//表示让步,thread线程直接进入就绪状态,在于其他线程共同竞争
}
System.out.println("j="+i);
}
});
thread.start();
thread1.start();
}
}
- 线程的停止或中断
- 设置bool值进行循环判断
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThread myThread=new MyThread();
myThread.start();
for (int i = 0; i < 10; i++) {
System.out.println("j="+i);
if(i==5){
myThread.stopFlag=true;
}
}
}
}
class MyThread extends Thread{
public boolean stopFlag;
@Override
public void run() {
for (int i = 0; i <100 && !stopFlag; i++) {
System.out.println("i="+i);
}
}
}
- 通过淘汰的thread.stop()
为什么会弃用呢:
为什么弃用stop:
调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
例如,存在一个对象 u 持有 ID 和 NAME 两个字段,假如写入线程在写对象的过程中,只完成了对 ID 的赋值,但没来得及为 NAME 赋值,就被 stop() 导致锁被释放,那么当读取线程得到锁之后再去读取对象 u 的 ID 和 Name 时,就会出现数据不一致的问题.
thread.stop()
- 通过thread.interrupt()
这个方法不同于stop()他不是立即终止线程,而是在目标线程中打一个标记,通过这个标记,更具需要处理你的代码。注意下面的代码:
public boolean Thread.isInterrupted() //判断是否被中断,静态方法
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态实例方法
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i = 0; i < 100; i++) {
if(Thread.currentThread().isInterrupted()){
break;
}
System.out.println(i);
}
System.out.println(Thread.currentThread().isInterrupted());//不会清除中断标志
System.out.println(Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread().isInterrupted());
});
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println("j="+i);
if(i==0){
thread.interrupt();
}
}
}
}
如果当前线程处于阻塞状态,比如sleep状态,当调用中断方法时会抛出异常,若希望中断发生就停止可以这么做
用try catch finally 包裹循环
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
int i=0;
try {
while (true){
System.out.println(i++);
Thread.sleep(1000);
}
}
catch (InterruptedException e){
}
finally {
System.out.println("释放资源的代码");
}
});
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println("j="+i);
if(i==0){
thread.interrupt();
}
}
}
}
三.线程的案例–闪烁的文本利用javafx实现
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch( args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Text text=new Text("Welcome");
new Thread(()->{
while (true){
if(text.getText().length()>0){
Platform.runLater(()->{
text.setText("");
});
}
else {
Platform.runLater(()->{//通知ui线程修改ui,子线程不能修改ui线程
text.setText("Welcome");
});
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
StackPane stackPane=new StackPane(text);
primaryStage.setScene(new Scene(stackPane));
primaryStage.show();
}
}
三.4种jdk内置的线程池(面试前要好好攻克补充难点)
1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2、提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.
CachedThreadPool适合多个轻量级任务,几乎可以创建无限个线程(整数最大值),如果超过60秒没有人用这个线程则会销毁这个资源,重复利用
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
Thread thread=null;
ExecutorService threadPool= Executors.newCachedThreadPool();//创建线程池
threadPool.execute(()->{//通过线程池中的线程运行任务
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
});
}
}
FixedThreadPool 固定大小的线程池,不会销毁,最好使用Runtime.getRuntime().availableProcessors()来获取系统可以并行的最大线程数,这样可以从分利用系统处理器
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
Thread thread=null;
ExecutorService threadPool= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
//创建固定大小线程池,最好使用Runtime.getRuntime().availableProcessors()
//来获取系统可以并行的最大线程数,这样可以从分利用系统处理器
threadPool.execute(()->{//通过线程池中的线程运行任务
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
});
}
}
newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
Thread thread=null;
ScheduledExecutorService threadPool= Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
//创建固定大小线程池,最好使用Runtime.getRuntime().availableProcessors()来获取系统可以并行的最大线程数,这样可以从分利用系统处理器
threadPool.schedule(()->{
return 5;
}, 3, TimeUnit.SECONDS);//3秒后执行有返回值的任务
threadPool.scheduleAtFixedRate(()->{
System.out.println(5);
},3,2,TimeUnit.SECONDS);//按固定周期执行任务
}
}
newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
Thread thread=null;
ExecutorService threadPool= Executors.newSingleThreadExecutor();
threadPool.execute(()->{
System.out.println(5);
});
}
}
四.向现称此种提交任务
- execute没有返回值,无法判断线程是否执行成功
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
Thread thread=null;
ExecutorService threadPool= Executors.newSingleThreadExecutor();
threadPool.execute(()->{
System.out.println(5);
});
}
}
- submit返回一个future 通过future中的get获取返回值,会阻塞线程
get(long timeout, TimeUnit unit)方法则会阻塞一段时间后立即返回,这时有可能任务没有执行完。
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread thread=null;
ExecutorService threadPool= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
java.util.concurrent.Future<Integer> future= threadPool.submit(()->{
int sum=0;
for (int i = 0; i <100; i++) {
sum+=i;
}
return sum;
});
System.out.println(future.get());
}
}
五.关闭线程池
可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。两者的区别是:shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread thread=null;
ExecutorService threadPool= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (int i = 0; i < 1000; i++) {
java.util.concurrent.Future<Integer> future= threadPool.submit(()->{
int sum=0;
for (int j = 0; j <100; j++) {
sum+=j;
}
return sum;
});
}
threadPool.shutdownNow();
System.out.println(threadPool.isShutdown());//只要调用了shut相关方法都会返回true
System.out.println( threadPool.isTerminated());//只有当所有任务成功关闭,才返回true
}
}
六.线程同步
- synchronized关键字
同步方法,如果时静态方法,这是锁住了这个类
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Acount acount=new Acount();
ExecutorService executorService=Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(()->{
try {
acount.add(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
while (!executorService.isTerminated()){
}
System.out.println(acount.getBlance());
}
}
class Acount{
private int blance;
public int getBlance() {
return blance;
}
public synchronized void add(int count) throws InterruptedException {//同步方法
int newBlance=blance+count;
Thread.sleep(50);
blance=newBlance;
}
}
同步代码块
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Acount acount=new Acount();
ExecutorService executorService=Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(()->{
try {
acount.add(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
while (!executorService.isTerminated()){
}
System.out.println(acount.getBlance());
}
}
class Acount{
private int blance;
public int getBlance() {
return blance;
}
public void add(int count) throws InterruptedException {//同步方法
synchronized (this){
int newBlance=blance+count;
Thread.sleep(50);
blance=newBlance;
}
}
}
显式锁(相互排斥的锁)Lock(抽象方法)
lock()得到一个锁
unlock()释放锁
newCondition()用此锁创建一个Condition实例,用作线程协作
ReentrantLock是Lock的一个实例
new ReentrantLock(boolen fair);为真则等待时间长的获取到锁概率高,但性能差点
new ReentrantLock()=new ReentrantLock(false)
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Acount acount=new Acount();
ExecutorService executorService=Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(()->{
try {
acount.add(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
while (!executorService.isTerminated()){
}
System.out.println(acount.getBlance());
}
}
class Acount{
private int blance;
private Lock lock=new ReentrantLock();
public int getBlance() {
return blance;
}
public void add(int count) throws InterruptedException {//同步方法
lock.lock();//获取到锁
try {
int newBlance=blance+count;
Thread.sleep(0);
blance=newBlance;
}
catch (InterruptedException e){
}
finally {
lock.unlock();//写在finally种是一个好习惯
}
}
}
七.线程之间的通信(监视器和这个的对比,后面注意去看下)–通过生产者和消费者的例子
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static void main(String[] args) {
Producer producer=new Producer(new Storeger());
ExecutorService executorService= Executors.newCachedThreadPool();
executorService.execute(()->{
try {
producer.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executorService.execute(()->{
try {
producer.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
class Producer{//生产者和消费者写在一起了
private Storeger storeger;
public Producer(Storeger storeger){
this.storeger=storeger;
}
public void add() throws InterruptedException {
while (true){
storeger.add();
}
}
public void get() throws InterruptedException {
while (true){
storeger.get();
}
}
}
class Storeger{
public static final int MAX_COUNT = 100;
private LinkedList<Integer> list=new LinkedList<>();
private Lock lock=new ReentrantLock();
private Condition isAdd=lock.newCondition();
private Condition isGet=lock.newCondition();
public void add(){
lock.lock();
try {
if (list.size()==MAX_COUNT){
isGet.await();//当仓库满了,我就要等待被获取的信号
}
System.out.println("添加10个数据 现在有"+list.size());
for (int i = 0; i < 10; i++) {
list.offerLast(i);
}
isAdd.signalAll();//每次添加了,就可以通知消费者进行消费了
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get(){
lock.lock();
try {
if (list.size()==0){
isAdd.await();
}
System.out.println("开始获得10个数据 现在有"+list.size());
for (int i = 0; i < 10; i++) {
list.pollLast();
}
isGet.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally
{
lock.unlock();
}
}
}
七.阻塞队列
阻塞队列能够在队列满的时候导致线程阻塞,必须另一个线程将他删除一个元素才能继续,
当空的 时候必须由另一个线程进行添加才能继续
put()添加到尾部,take()从头部删除元素
ArrayBlockingQueue 指定容量和公平策略,数组实现
LinkedBlockingQueue 如果不指定容量put()方法将不会阻塞
PriorityBlockingQueue 元素按优先级排序
还有其他的了解下
通过这些阻塞队列我们能够更方便实现生产者和消费者模式
八.信号量(了解下)–限定访问某个资源的线程数量
九.死锁
有两个或多个对象需要在共享对象上获取锁,就会造成死锁
class Producer{
Lock lock=new ReentrantLock();
Lock lock1=new ReentrantLock();
public void add(){
lock.lock();
lock1.lock();
try {
}
finally {
lock1.unlock();
lock.unlock();
}
}
public void get(){
lock1.lock();
lock.lock();
try {
}
finally {
lock.unlock();
lock1.unlock();
}
}
}
避免死锁的机制
就是获取锁的顺序一致,资源排序
十.线程状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrkpNth1-1595654695657)(img/1.png)]
十一.同步合集
public class Main {
public static void main(String[] args) {
Collections.synchronizedCollection()//创建同步合集
Collections.synchronizedList()//同步线性表
Collections.synchronizedMap()//同步映射表
Collections.synchronizedSet()//同步集合
Collections.synchronizedSortedMap()
}
}
十二.利用fork/join框架进行并行编程
- 用继承于RecursiveTask或RecursiveAction,其中一个可以返回值,然后重写里面compute方法
其中的fork()表示创建一个异步任务分支,
join()表示等待分支任务完成
invoke()内部其实就是fork和join
invokeAll(tasks)//多个分支 - 创建ForkJoinPool调用invoke()方法
实战1. 合并排序的并行实现和普通实现
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class Main {
public static void main(String[] args){
int[] arr=new int[50000000];
for (int i = 0; i < 50000000; i++) {
arr[i]=(int)(Math.random()*100+1);
}
long start2= Instant.now().toEpochMilli();
new SortOther(arr).compute();
long end2= Instant.now().toEpochMilli();
System.out.println(end2-start2);
long start1= Instant.now().toEpochMilli();
ForkJoinPool forkJoinPool=new ForkJoinPool();
forkJoinPool.invoke(new SortTask(arr));
long end1= Instant.now().toEpochMilli();
System.out.println(end1-start1);
}
}
//普通实现
class SortOther{
private int[] arr;
public static final int HOLD_THREAD=500;
public SortOther(int[] arr){
this.arr=arr;
}
protected void compute() {
if(arr.length<HOLD_THREAD){
Arrays.sort(arr);
}
else {
int[] firstArr=new int[arr.length/2];
int[] lastArr=new int[arr.length-arr.length/2];
System.arraycopy(arr, 0, firstArr, 0, arr.length/2);
System.arraycopy(arr, arr.length/2, lastArr, 0, arr.length-arr.length/2);
new SortOther(firstArr).compute();
new SortOther(lastArr).compute();
merge(firstArr, lastArr, arr);
}
}
protected void merge(int[] first,int[] last,int[] list){
System.arraycopy(first,0,list,0,first.length);
System.arraycopy(last,0,list,first.length,last.length);
Arrays.sort(list);
}
}
//并行实现
class SortTask extends RecursiveAction {
private int[] arr;
public static final int HOLD_THREAD=500;
public SortTask(int[] arr){
this.arr=arr;
}
@Override
protected void compute() {
if(arr.length<HOLD_THREAD){
Arrays.sort(arr);
}
else {
int[] firstArr=new int[arr.length/2];
int[] lastArr=new int[arr.length-arr.length/2];
//0 1 2 3 4 5 6 7 8
System.arraycopy(arr, 0, firstArr, 0, arr.length/2);
System.arraycopy(arr, arr.length/2, lastArr, 0, arr.length-arr.length/2);
invokeAll(new SortTask(firstArr),new SortTask(lastArr));
merge(firstArr, lastArr, arr);
}
}
protected void merge(int[] first,int[] last,int[] list){
System.arraycopy(first,0,list,0,first.length);
System.arraycopy(last,0,list,first.length,last.length);
Arrays.sort(list);
}
}
实战2 并行求和
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class Main {
public static void main(String[] args){
long start2= Instant.now().toEpochMilli();
ForkJoinPool forkJoinPool=new ForkJoinPool();
long sum=forkJoinPool.invoke(new ParallelSum(0, 500000));
System.out.println(sum);
long end2= Instant.now().toEpochMilli();
System.out.println(end2-start2);
}
}
class ParallelSum extends RecursiveTask<Long> {
public final static int THREAD_HOLD=500;
private long from;
private long to;
public ParallelSum(long from,long to){
this.from=from;
this.to=to;
}
@Override
protected Long compute() {
long len=to-from;
if(len<=THREAD_HOLD){
long sum=0;
for (long i = from; i <to ; i++) {
sum+=i;
}
return sum;
}
else {
long middle=(from+to)/2;
ParallelSum parallelSum=new ParallelSum(from,middle);
ParallelSum parallelSum1=new ParallelSum(middle+1, to);
parallelSum.fork();
parallelSum1.fork();
return parallelSum.join()+parallelSum1.join();
}
}
}
实战3 并行找最大值
import java.time.Instant;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class Main {
public static void main(String[] args){
int[] arr=new int[1000000];
Random random=new Random(System.currentTimeMillis());
for (int i = 0; i < 1000000; i++) {
arr[i]=random.nextInt(9048);
}
long start2= Instant.now().toEpochMilli();
ForkJoinPool forkJoinPool=new ForkJoinPool();
long sum=forkJoinPool.invoke(new ParallelMax(arr));
System.out.println(sum);
long end2= Instant.now().toEpochMilli();
System.out.println(end2-start2);
}
}
class ParallelMax extends RecursiveTask<Integer> {
public final static int THREAD_HOLD=2;
private int[] list;
public ParallelMax(int[] arr){
list=arr;
}
@Override
protected Integer compute() {
if(list.length==THREAD_HOLD){
return Math.max(list[0],list[1]);
}
else if(list.length==1){
return list[0];
}
else if(list.length==0){
return null;
}
else {
int[] first=new int[list.length/2];
int[] last=new int[list.length-list.length/2];
System.arraycopy(list, 0, first, 0, list.length/2);
System.arraycopy(list, list.length/2, last, 0, list.length-list.length/2);
ParallelMax parallelMax=new ParallelMax(first);
ParallelMax parallelMax1=new ParallelMax(last);
parallelMax.fork();
parallelMax1.fork();
return parallelMax.join()>parallelMax1.join()?parallelMax.join():parallelMax1.join();
}
}
}
实战4 并行统计文件大小
import java.io.File;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class Main {
//普通递归
public static long getDirSize(File dir) {
if (dir == null) {
return 0;
}
if (!dir.isDirectory()) {
return 0;
}
long dirSize = 0;
File[] files = dir.listFiles();
if(files!=null){
for (File file : files) {
if (file.isFile()) {
dirSize += file.length();
} else if (file.isDirectory()) {
dirSize += file.length();
dirSize += getDirSize(file); // 如果遇到目录则通过递归调用继续统计
}
}
}
return dirSize;
}
public static void main(String[] args){
ForkJoinPool forkJoinPool=new ForkJoinPool();
long start2= Instant.now().toEpochMilli();
//long size=forkJoinPool.invoke(new ParallelFileSize(new File("C:\\")));
long size=getDirSize(new File("C:\\"));
long end2= Instant.now().toEpochMilli();
System.out.println(size);
System.out.println(end2-start2);
long start1= Instant.now().toEpochMilli();
long size1=forkJoinPool.invoke(new ParallelFileSize(new File("C:\\")));
//long size=getDirSize(new File("C:\\"));
long end1= Instant.now().toEpochMilli();
System.out.println(end1-start1);
System.out.println(size1);
}
}
//并行递归
class ParallelFileSize extends RecursiveTask<Long>{
private long size=0;
private File file;
public ParallelFileSize(File file){
this.file=file;
}
@Override
protected Long compute() {
if(file==null){
return null;
}
else {
if(file.isFile()){
size+=file.length();
}
else {
File[] files=file.listFiles();
if(files!=null){
ParallelFileSize[] parallelFileSizes =new ParallelFileSize[files.length];
for (int i = 0; i <files.length ; i++) {
parallelFileSizes[i]=new ParallelFileSize(files[i]);
parallelFileSizes[i].fork();
}
for (int i = 0; i <files.length ; i++) {
size+= parallelFileSizes[i].join();
}
}
}
}
return size;
}
}
private long size=0;
private File file;
public ParallelFileSize(File file){
this.file=file;
}
@Override
protected Long compute() {
if(file==null){
return null;
}
else {
if(file.isFile()){
size+=file.length();
}
else {
File[] files=file.listFiles();
if(files!=null){
ParallelFileSize[] parallelFileSizes =new ParallelFileSize[files.length];
for (int i = 0; i <files.length ; i++) {
parallelFileSizes[i]=new ParallelFileSize(files[i]);
parallelFileSizes[i].fork();
}
for (int i = 0; i <files.length ; i++) {
size+= parallelFileSizes[i].join();
}
}
}
}
return size;
}
}