多线程编程

总结:使用实现多线程有四种方式:
1.继承Thread类;
2.实现Runnable接口;
3.使用Callable和FutureTask实现有返回值的多线程;
4.使用ExecutorService和Executors工具类实现线程池(如果需要线程的返回值,需要在线程中实现Callable和Future接口)

public class MyThread extends Thread {
    private int threadId;
    
    public MyThread(int threadId) {
        this.threadId = threadId;
    }
    
    @Override
    public void run() {
        //代码逻辑
        System.out.println("Hello, I'm thread " + threadId);
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread(1);
        MyThread thread2 = new MyThread(2);
        
        thread1.start();
        thread2.start();
    }
}
@Test
public void testRunableThread() {
    List<Address> addressList = addressService.list();

    //计算器,初始值是线程总数,依次递减,当等于0时,全部任务完成
    CountDownLatch latch = new CountDownLatch(addressList.size());
    for (Address address : addressList) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                address.setList(liverService.list(Wrappers.<Liver>lambdaQuery().eq(Liver::getAddressId, address.getId())));
                //每次一个线程任务完成-1
                latch.countDown();
            }
        });
        thread.start();
    }
    try {
        //主线程等待latch==0时执行
        latch.await();
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("addressList的数据为:::" + addressList);
}

注:CountDownLatch是Java的一个多线程同步工具,它可以用来协调多个线程的执行。CountDownLatch本身是线程安全的,因为它内部使用了原子操作和线程安全的机制。
CountDownLatch是一个计数器, 初始值为线程的总数
CountDownLatch.countDown();该方法每次都会 CountDownLatch-1 操作
CountDownLatch.await(); 该方法所在线程会等 CountDownLatch=0 时才会执行后续操作

 @Test
 public void testallableThread() {

        List<Address> addressList = addressService.list();

        //计算器,初始值是线程总数,依次递减,当等于0时,全部任务完成
        CountDownLatch latch = new CountDownLatch(addressList.size());
        List<FutureTask<List<Liver>>> taskList = new ArrayList<>(addressList.size());

        for (Address address : addressList) {
            FutureTask<List<Liver>> futureTask = new FutureTask<>(new Callable<List<Liver>>() {
                @Override
                public List<Liver> call() {
                    List<Liver> liverList = liverService.list(Wrappers.<Liver>lambdaQuery().eq(Liver::getAddressId, address.getId()));
                    address.setList(liverList);
                    //每次一个线程任务完成-1
                    latch.countDown();
                    return liverList;
                }
            });
            taskList.add(futureTask);
            Thread thread = new Thread(futureTask);
            thread.start();
        }
        CompletableFuture.supplyAsync(new Supplier<Object>() {
            @Override
            public Object get() {
                return null;
            }
        });
        try {
            //主线程等待latch==0时执行
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<Liver> liverList = new ArrayList<>();
        for (FutureTask<List<Liver>> futureTask : taskList) {
            List<Liver> livers = new ArrayList<>();
            try {
                //获取每条线程返回结果
                livers = futureTask.get();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                liverList.addAll(livers);
            }
        }
        System.out.println("addressList的数据为:::" + addressList);
        System.out.println("liverList的数据为:::" + liverList);
    }
}

注:thread默认参数时runable类型,所以如果需要使用thread运行callable,可以使用FutureTask封装一下
FutureTask底层继承了runable接口接口和获取callable执行结果Future接口

public class ThreadPool {
    
    // 最大线程数
    public static final int THREAD_POOL_SIZE = 20;
    
//    创建指定线程数量的线程池
//    ExecutorService ExecutorService = Executors.newFixedThreadPool(10);

    /**
     * 创建线程工厂,自定义线程命名前缀
     */
    public static ThreadFactory namedThreadFactory() {
        return new ThreadFactoryBuilder().setNameFormat("order-runner-%d").build();
    }
   /**
     * 创建线程池,其中任务队列需要结合实际情况设置合理的容量
     * newFixedThreadPool 创建指定线程线程池
     * newFixedThreadPool 创建指定线程线程
     */
    public static ExecutorService MyThreadPoolExecutor(int nThreads) {
        return new ThreadPoolExecutor(
                // 核心线程数
                nThreads,
                // 最大线程数
                THREAD_POOL_SIZE,
                // 空闲线程存活时间
                0L,
                // 空闲线程存活时间单位
                TimeUnit.SECONDS,
                // 任务队列
                new LinkedBlockingQueue<>(),
                //线程名称
                namedThreadFactory()
        );
    }
    @Test
    public void testCompletionThread() {
        
        List<Address> addressList = addressService.list();
        //获取线程池
        ExecutorService executorService = ThreadPool.MyThreadPoolExecutor(addressList.size());
        //ExecutorCompletionService来并发获取任务结果
        ExecutorCompletionService<List<Liver>> completionService = new ExecutorCompletionService<>(executorService);

        for (Address address : addressList) {
            completionService.submit(new Callable<List<Liver>>() {
                @Override
                public List<Liver> call(){
                    List<Liver> liverList = liverService.list(Wrappers.<Liver>lambdaQuery().eq(Liver::getAddressId, address.getId()));
                    address.setList(liverList);
                    return liverList;
                }
            });
        }

        List<Liver> liverList = new ArrayList<>();
        try {
            for (int i = 0; i < addressList.size(); i++) {
                //所有线程完成之后使用ExecutorCompletionService.take方法获取结果集
                Future<List<Liver>> future = completionService.take();
                List<Liver> livers = future.get();
                liverList.addAll(livers);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();

        System.out.println("addressList数据为:::" + addressList);
        System.out.println("liverList数据为:::" + liverList);
    }
//executorService为线程池对象
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executorService);
// 获取已完成的任务
Future<String> future = completionService.take(); 
// 获取任务结果
String str = future.get(); 
System.out.println(str);

注:在此实例中使用ExecutorCompletionService非阻塞获取返回值,ExecutorCompletionService可以用来并发获取结果集

  • 阻塞获取结果:take()方法是阻塞的,它会等待直到有任务完成并返回已完成的Future对象。如果队列中没有已完成的任务,则会一直阻塞。
  • 非阻塞获取结果:poll()方法可以立即返回一个已完成的Future对象,如果队列中没有已完成的任务,则返回null。
    @Test
    public void testThreadPool() {

        List<Address> addressList = addressService.list();

        ExecutorService executorService = ThreadPool.MyThreadPoolExecutor(addressList.size());
        //计算器,初始值是线程总数,依次递减,当等于0时,全部任务完成
        CountDownLatch latch = new CountDownLatch(addressList.size());
        List<FutureTask<List<Liver>>> list = new ArrayList<>(addressList.size());

        for (Address address : addressList) {
            FutureTask<List<Liver>> futureTask = new FutureTask<>(new Callable<List<Liver>>() {
                @Override
                public List<Liver> call() {
                    List<Liver> liverList = liverService.list(Wrappers.<Liver>lambdaQuery().eq(Liver::getAddressId, address.getId()));
                    address.setList(liverList);
                    //每次一个线程任务完成-1
                    latch.countDown();
                    return liverList;
                }
            });
            executorService.submit(futureTask);
            list.add(futureTask);
        }
        List<Liver> liverList = new ArrayList<>();
        try {
            //主线程等待latch==0时执行
            latch.await();
            for (FutureTask<List<Liver>> futureTask : list) {
                List<Liver> livers = futureTask.get();
                liverList.addAll(livers);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException(e.getMessage());
        }

        System.out.println("addressList数据为:::" + addressList);
        System.out.println("liverList数据为:::" + liverList);
    }

区别和使用场景 runable和callable的区别在于runable是没有返回值的,callable有返回值
使用线程池时,如果需要不需要获取返回结果使用runable调用run方法即可,如果需要获取返回值则使用callable调用call方法获取返回值
线程池executorService.sumit()方法 提交任务到线程池,并可以获取执行结果,一般搭配callable使用
线程池executorService.execute()方法 也是让线程池执行任务,但是没有办法获取返回值,一般搭配runable使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值