多线程-3

线程池
概念
线程池(Thread Pool)使用池化技术管理和使用线程的机制。通俗说,就是事先把一个或者多个线程放入池子中,当任务执行时,直接使用线程,用完后不是关闭线程,而是归还到池子中,方便复用。
好处

主要类和分类方式
主要类
Executors
是线程池的基础类,线程池用的接口或者类都是通过该类创建或者返回的。
工厂和工具方法Executor , ExecutorService , ScheduledExecutorService , ThreadFactory和Callable在此包中定义的类。 该类支持以下几种方法:
创建并返回一个ExecutorService设置的常用的配置设置的方法。
创建并返回一个ScheduledExecutorService的方法, 其中设置了常用的配置设置。
创建并返回“包装”ExecutorService的方法,通过使实现特定的方法无法访问来禁用重新配置。
创建并返回将新创建的线程设置为已知状态的ThreadFactory的方法。
创建并返回一个方法Callable出的其他闭包形式,这样他们就可以在需要的执行方法使用Callable 。
ExecutorService
一个Executor ,提供方法来管理终端和方法,可以产生Future为跟踪一个或多个异步任务执行。
一个ExecutorService可以关闭,这将导致它拒绝新的任务。 提供了两种不同的方法来关闭ExecutorService 。 shutdown()方法将允许先前提交的任务在终止之前执行,而shutdownNow()方法可以防止等待任务启动并尝试停止当前正在执行的任务。
分类方式
固定大小的线程池(FixedThreadPool)
简介
创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。
应用场景
已知服务器性能,使用固定大小的线程池,防止服务器因为线程过多,压力大而宕机。
实战

package com.aaa.mt.demo1;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @FileName: FixedThreadPoolDemo
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/26 9:37
 * @Version: 1.0.0
 */
public class FixedThreadPoolDemo {
    public static void main(String[] args) {
        //使用Executors创建固定长度的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //同时启动100个线程。。。
        for (int i = 0; i < 100; i++) {
            //启动线程,执行业务
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
                }
            });
        }

        //executorService.submit();
        //等线程业务执行完,再关闭
        executorService.shutdown();
        //立即关闭
        //executorService.shutdownNow();

    }
}

带缓冲的线程池(CachedThreadPool)
简介
创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
应用场景
适合大量短时任务执行,否则一定会因为线程多,压力大让服务器宕机。
实战

package com.aaa.mt.demo1;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @FileName: FixedThreadPoolDemo
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/26 9:37
 * @Version: 1.0.0
 */
public class CachedThreadPoolDemo {
    public static void main(String[] args) {
        //使用Executors创建固定长度的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        //同时启动100个线程。。。
        for (int i = 0; i < 100; i++) {
            //启动线程,执行业务
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
                }
            });
        }

        //executorService.submit();
        //等线程业务执行完,再关闭
        executorService.shutdown();
        //立即关闭
        //executorService.shutdownNow();

    }
}

单线程执行器(SingleThreadExecutor)
简介
建一个使用从无界队列运行的单个工作线程的执行程序。
应用场景
适合任务有序执行的场景。
实战

package com.aaa.mt.demo1;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @FileName: FixedThreadPoolDemo
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/26 9:37
 * @Version: 1.0.0
 */
public class SingleThreadExecutorDemo {
    public static void main(String[] args) {
        //使用Executors创建固定长度的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //同时启动100个线程。。。
        for (int i = 0; i < 100; i++) {
            //启动线程,执行业务
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
                }
            });
        }

        //executorService.submit();
        //等线程业务执行完,再关闭
        executorService.shutdown();
        //立即关闭
        //executorService.shutdownNow();

    }
}

带调度的线程池(ScheduledThreadPool)

简介
创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
应用场景
适合线程延迟或者定期执行。
实战

package com.aaa.mt.demo1;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @FileName: FixedThreadPoolDemo
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/26 9:37
 * @Version: 1.0.0
 */
public class ScheduledThreadPoolDemo {
    public static void main(String[] args) {
        //使用Executors创建固定长度的线程池
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        //延迟执行
        /*scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
            }
        },10, TimeUnit.SECONDS);*/

        //延迟加定期执行     两次开始时间的间隔  如果业务执行时间小于间隔时间   按照开始时间进行间隔
        //                                    如果业务执行时间打于间隔时间   按照业务执行时间进行间隔
       /* scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("开始执行时间是----------------------:"+new Date());
                System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
                try {
                    Thread.sleep(7000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("结束时间是:"+new Date());
            }
        },5,5,TimeUnit.SECONDS);*/
        //延迟加定期执行     上一次结束时间到下一次开始时间,间隔5秒   
        scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("开始执行时间是----------------------:"+new Date());
                System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("结束时间是:"+new Date());
            }
        },2,5,TimeUnit.SECONDS);

    }
}

核心参数
准备工作

Executors.newFixedThreadPool(5)->new ThreadPoolExecutor->ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)->this()->ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)


工作原理

拒绝策略

submit和execute区别?
execute(Runnable run) : 只能执行Runnable的子类, 没有返回值和异常处理

submit(Runnable run/Callable call) :技能执行Runnable的子类,还能执行Callable子类,有返回值和异常处理
实战

package com.aaa.mt.demo1;

import java.sql.SQLOutput;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * @FileName: FixedThreadPoolDemo
 * @Description:Execute和Submit区别
 * @Author: zhz
 * @CreateTime: 2024/11/26 9:37
 * @Version: 1.0.0
 */
public class ExecuteAndSubmitDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //使用Executors创建固定长度的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

            //启动线程,执行业务
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
                }
            });
        //启动线程,执行业务   放Callable直接报红
        /*executorService.execute(new Callable<String>(){
            @Override
            public String call() throws Exception {
                return null;
            }
        });*/
        //submit执行Runnable的子类
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"正在执行,在执行xxx任务!!!");
            }
        });
        //submit执行Callable的子类
        Future<String> resultFuture = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName() + "正在执行,在执行xxx任务!!!");
                String randomStr = UUID.randomUUID().toString();
                System.out.println("随机生成的字符串:" + randomStr);
                int[] intArray = {1,2,3};
                //System.out.println(intArray[3]);
                return randomStr;
            }
        });

        //获取返回值
        String returnValue = resultFuture.get();
        System.out.println("返回值为:"+returnValue);
        //executorService.submit();
        //等线程业务执行完,再关闭
        executorService.shutdown();
        //立即关闭
        //executorService.shutdownNow();

    }
}

多线程实战
需求
使用多线程测试全班的IP是否通畅,使用单线程和多线程两种方式来完成,观察使用时间。实战中知道多线程提高任务执行效率。
单线程

package com.aaa.mt.demo2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @FileName: SingleThreadPingIP
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/26 15:02
 * @Version: 1.0.0
 */
public class SingleThreadPingIP {

    /**
     * 封装通用的方法
     * @param ip
     */
    public static void pingIP(String ip){
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            //获取Runtime类的对象
            //每个Java应用程序都有一个Runtime类的Runtime ,允许应用程序与运行应用程序的环境进行接口。
            Runtime runtime = Runtime.getRuntime();
            //使用runtime对象执行cmd命令,并返回进程对象    进程对象包含输出流,输出流,错误流
            Process process = runtime.exec("ping "+ip);
            //使用process获取输入流
            inputStream = process.getInputStream();
            //把字节流转为缓存字符流,能提高速度,防止乱码
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream,"GB2312"));
            //定义空字符串接受值
            String readMsg = null;
            //定义标识符
            boolean isTrue = false;
            //循环读取     readMsg=bufferedReader.readLine() 读取一行并赋值给readMsg
            while((readMsg=bufferedReader.readLine())!=null){
                //System.out.println(readMsg);
                //判断结果中是否含有TTL,如果含有说明IP通畅 否则不同
                if(readMsg.contains("TTL")){
                    //System.out.println("172.16.2.75 通畅!");
                    isTrue=true;
                    break;
                }
                if(readMsg.contains("无法访问目标主机")){
                    //System.out.println("172.16.2.75 通畅!");
                    //isTrue=true;
                    break;
                }
            }
            //判断标识符
            if(isTrue){
                System.out.println(ip+"通畅");
            }else {
                System.out.println(ip+"不通畅");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
                if(bufferedReader!=null){
                    bufferedReader.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args)   {
        //测试所有IP是否通畅
        //获取当前时间到1970年1月1号0点的毫秒
        long start = System.currentTimeMillis();
        //循环
        for (int i = 2; i <= 52; i++) {
            pingIP("172.16.2."+i);
        }
        //获取当前时间到1970年1月1号0点的毫秒
        long end = System.currentTimeMillis();
        //执行时间为:
        System.out.println("执行时间为:"+(end-start)/1000+"秒");

    }
}

多线程(实现Runnable或者使用线程池)

package com.aaa.mt.demo2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @FileName: SingleThreadPingIP
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/26 15:02
 * @Version: 1.0.0
 */
public class MultiThreadPingIP implements Runnable{

    //因为在run方法中想使用ip  定义属性,然后使用构造方法赋值
    private String ip;

    /**
     * 构造方法赋值
     * @param ip
     */
    public MultiThreadPingIP(String ip) {
        this.ip = ip;
    }

    @Override
    public void run() {
        pingIP(ip);
    }

    /**
     * 封装通用的方法
     * @param ip
     */
    public static void pingIP(String ip){

        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            //获取Runtime类的对象
            //每个Java应用程序都有一个Runtime类的Runtime ,允许应用程序与运行应用程序的环境进行接口。
            Runtime runtime = Runtime.getRuntime();
            //使用runtime对象执行cmd命令,并返回进程对象    进程对象包含输出流,输出流,错误流
            Process process = runtime.exec("ping "+ip);
            //使用process获取输入流
            inputStream = process.getInputStream();
            //把字节流转为缓存字符流,能提高速度,防止乱码
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream,"GB2312"));
            //定义空字符串接受值
            String readMsg = null;
            //定义标识符
            boolean isTrue = false;
            //循环读取     readMsg=bufferedReader.readLine() 读取一行并赋值给readMsg
            while((readMsg=bufferedReader.readLine())!=null){
                //System.out.println(readMsg);
                //判断结果中是否含有TTL,如果含有说明IP通畅 否则不同
                if(readMsg.contains("TTL")){
                    //System.out.println("172.16.2.75 通畅!");
                    isTrue=true;
                    break;
                }
                if(readMsg.contains("无法访问目标主机")){
                    //System.out.println("172.16.2.75 通畅!");
                    //isTrue=true;
                    break;
                }
            }
            //判断标识符
            if(isTrue){
                System.out.println(ip+"通畅");
            }else {
                System.out.println(ip+"不通畅");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
                if(bufferedReader!=null){
                    bufferedReader.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args)   {
        //测试所有IP是否通畅
        //获取当前时间到1970年1月1号0点的毫秒
        //long start = System.currentTimeMillis();
        //循环
      /*  for (int i = 2; i <= 52; i++) {
             new Thread(new MultiThreadPingIP("172.16.2."+i)).start();
        }*/
        //获取当前时间到1970年1月1号0点的毫秒
        //long end = System.currentTimeMillis();
        //执行时间为:
       // System.out.println("执行时间为:"+(end-start)/1000+"秒");
        ExecutorService executorService = Executors.newFixedThreadPool(30);
        for (int i = 2; i <= 32; i++) {
          final   int j = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {

                    MultiThreadPingIP.pingIP("172.16.2."+j+",线程名字为:"+Thread.currentThread().getName());
                }
            });

        }
        executorService.shutdown();

    }
}

posted on 2024-12-29 17:05  小木不痞  阅读(8)  评论(0)    收藏  举报

导航