# Java 常用代码片段

Posted 爱码代码的喵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# Java 常用代码片段相关的知识,希望对你有一定的参考价值。

Java 常用代码片段

延迟队列

  • JDK 中提供了一组实现延迟队列的API,位于Java.util.concurrent包下DelayQueue
    DelayQueue是一个BlockingQueue(无界阻塞)队列,它本质就是封装了一个PriorityQueue(优先队列),PriorityQueue内部使用完全二叉堆(来实现队列元素排序,我们在向DelayQueue队列中添加元素时,会给元素一个Delay(延迟时间)作为排序条件,队列中最小的元素会优先放在队首。队列中的元素只有到了Delay时间才允许从队列中取出。

  • DelayDemo.java

public class DelayDemo implements Delayed 

    /**
     * 延迟时间
     */
    @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Long time;

    /**
     * 任务名称
     */
    private String name;


    public DelayDemo(Long time, String name, TimeUnit unit) 
        this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
        this.name = name;
    

    /**
     * 获取延迟时间
     *
     * @param unit unit
     * @return long
     */
    @Override
    public long getDelay(TimeUnit unit) 
        return time - System.currentTimeMillis();
    

    /**
     * 对延迟队列中的元素进行排序
     *
     * @param o
     * @return int
     */
    @Override
    public int compareTo(Delayed o) 
        DelayDemo delayDemo = (DelayDemo) o;
        return time.compareTo(delayDemo.getTime());
    

    public Long getTime() 
        return time;
    

    public void setTime(Long time) 
        this.time = time;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

  • DelayQueueTest.java
public class DelayQueueTest 

    private static final Logger logger = LoggerFactory.getLogger(DelayQueueTest.class);

    @Test
    public void test() throws InterruptedException 
        DelayDemo delayDemo1 = new DelayDemo(5l, "订单1", TimeUnit.SECONDS);
        DelayDemo delayDemo2 = new DelayDemo(10l, "订单2", TimeUnit.SECONDS);
        DelayDemo delayDemo3 = new DelayDemo(15l, "订单3", TimeUnit.SECONDS);

        DelayQueue<DelayDemo> delayQueue = new DelayQueue<>();
        delayQueue.add(delayDemo1);
        delayQueue.add(delayDemo2);
        delayQueue.add(delayDemo3);

        logger.info("延迟队列开始时间:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        while (delayQueue.size() != 0) 
            DelayDemo delayDemo = delayQueue.poll();
            if (Objects.nonNull(delayDemo)) 
                logger.info("任务:" + delayDemo.getName() + "被取消, 取消时间: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            
            Thread.sleep(1000);
        
    

线程池 ThreadPoolExecutor

参数说明

  • corePoolSize:核心线程数
  • maxPoolSize:最大线程数,当阻塞队列满了的时候会使用最大线程数的线程提交任务
  • keepAliveTime:线程空闲的时候保持活跃的时间

队列

  • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序
  • LinkedBlockingQueue一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
  • SynchronousQueue:不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
  • PriorityBlockingQueue:具有优先级的无限阻塞队列。

拒绝策略

  • 当提交的任务数大于队列和最大线程数的时候就会触发线程池的拒绝策略。

  • AbortPolicyThreadPoolExecutor中默认的拒绝策略就是AbortPolicy,直接抛出异常。

  • CallerRunsPolicy :使用该策略时线程池饱和后将由调用线程池的主线程自己来执行任务,因此在执行任务的这段时间里主线程无法再提交新任务,从而使线程池中工作线程有时间将正在处理的任务处理完成。

  • DiscardPolicy :不做任何处理直接抛弃任务。

  • DiscardOldestPolicy :先将阻塞队列中进入最早的任务丢弃,再尝试提交任务。

示例代码

@Test
public void test2() 
    // 核心线程数
    int corePoolSize = Runtime.getRuntime().availableProcessors() + 1;
    // 最大线程数
    int maxPoolSize = Runtime.getRuntime().availableProcessors() << 1;
    // 当线程空闲时,保持活跃的时间 1000 毫秒 1s
    int keepAliveTime = 1000;
    // 阻塞队列大小
    int blockQueueSize = 1000;

    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,
                                                           maxPoolSize,
                                                           keepAliveTime,
                                                           TimeUnit.MILLISECONDS,
                                                           new LinkedBlockingQueue<>(blockQueueSize),
                                                           new ThreadPoolExecutor.AbortPolicy());

    threadPool.execute(() -> 
        logger.info("自定义线程池的使用...");
    );
    try 
        Thread.sleep(3000);
     catch (InterruptedException e) 
        logger.error("Error occur:", e);
    

创建线程

获取线程执行结果(Callable)

  • 可以拿到线程中抛出的异常。
  • 线程执行完成后可以返回结果。

示例

  • DoOneCallable.java
public class DoOneCallable implements Callable<Object> 

    private static final Logger logger = LoggerFactory.getLogger(DoOneCallable.class);

    @Override
    public Object call() 
        try 
            logger.info("test Thread!");
            return 4 / 0;
         catch (Exception e) 
            throw e;
        
    

  • CallableTest.java
public class CallableTest 

    private static final Logger logger = LoggerFactory.getLogger(CallableTest.class);

    /**
     * Callable 的使用场景:加入子线程中有错误抛出、或者拿到线程执行的结果
     *
     * @param args args
     */
    public static void main(String[] args) 
        Callable<Object> callable = new DoOneCallable();
        FutureTask<Object> futureTask = new FutureTask<>(callable);
        try 
            // run 方法启动线程
            futureTask.run();
            // get() 获得当前线程的执行结果
            futureTask.get();
         catch (Exception e) 
            logger.error("Error occur:", e.getMessage());
        
        logger.info("hello!");
    

    /**
     * callable 可以拿到线程中的异常
     */
    @Test
    public void test() 
        Callable<Object> callable = new DoOneCallable();
        try 
            callable.call();
         catch (Exception e) 
            logger.error("Error occur:", e.getMessage());
        
    

实现Runnable

  • 使用Runnable创建线程可以达到共享资源的目的
  • 外部无法捕获线程中的异常和结果

示例

public class CreateThreadByRunnableTest 

    private static final Logger logger = LoggerFactory.getLogger(CreateThreadByRunnableTest.class);
    private static final int TICKET_NUM = 11;

    /**
     * 使用 Runnable 的方式创建代码可以达到相同代码公用共同的资源
     */
    @Test
    public void test() 
        int num = 10;
        BuyTicketsRunnable buyTicketsRunnable = new BuyTicketsRunnable(num);
        for (int i = 0; i < TICKET_NUM; i++) 
            Thread thread = new Thread(buyTicketsRunnable);
            thread.start();
            if (Thread.holdsLock(Thread.currentThread())) 
                logger.info("当前线程持有对象监视器!");
            
        
    

    class BuyTicketsRunnable implements Runnable 

        private final Logger logger = LoggerFactory.getLogger(BuyTicketsRunnable.class);

        private int num;

        BuyTicketsRunnable(int ticketNum) 
            this.num = ticketNum;
        

        @Override
        public void run() 
            synchronized (this) 
                if (num > 0) 
                    num--;
                    logger.info("Thread  买到一张票 还剩: 张票", Thread.currentThread().getId(), num);
                 else 
                    logger.info("Thread  没有抢到票 还剩: 张票", Thread.currentThread().getId(), num);
                
            
        
    

继承Thread重写run()

  • 继承Thread,重写run方法,Thread类实现Runnable接口
  • class Thread implements Runnable

示例代码

public class CreateThreadByThreadTest 

    private static final Logger logger = LoggerFactory.getLogger(CreateThreadByThreadTest.class);

    @Test
    public void test() 
        new TestExtendsThread().start();
    

    class TestExtendsThread extends Thread 
        @Override
        public void run() 
            logger.info("我是Test1ExtendsThread的线程!");
        
    

Executors四种类型的线程池

  • 通过源码分析得出还是对ThreadPoolExecutor的使用,指定对应参数达到一定的效果

newFixedThreadPool

  • newFixedThreadPool(n):创建一个指定工作线程数量的线程池,如果线程数量达到初始化大小,则将提交的任务保存到池队列中。提高效率节省开销,不会释放空闲资源。
public static void userFixThreadPool() throws InterruptedException 
    ExecutorService executor = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) 
        Thread.sleep(1000);
        int index = i;
        executor.execute(() -> 
            try 
                Thread.sleep(2 * 1000);
             catch (InterruptedException e) 
                logger.error(e.getMessage(), e);
            
            logger.info("  ", Thread.currentThread().getName(), index);
        );
    
    executor.shutdown();

newCachedThreadPool

  • newCachedThreadPool():缓存线程池,可以灵活收回空闲线程,若无可回收则创建新的。默认为1分钟。
private void useCachedThreadPool(int y) throws Exception 
    ExecutorService executor = Executors.newCachedThreadPool();
    for (int i = 0; i < y; i++) 
        int index = i;
        Thread.sleep(4000);
        executor.execute(() -> logger.info("  ", Thread.currentThread().getName(), index));
    

newSingThreadExcutor

  • newSingThreadExcutor():只创建唯一的工作线程来执行任务,保证线程按照指定的书序执行,保证顺序的执行任务。
private void useSingleThreadExecutor() 
    // 单线程的线程池底层是创建一个核心线程为1最大线程为1的 threadPool
    ExecutorService executor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 5; i++) 
        int index = i;
        executor.execute(() -> 
            try 
                Thread.sleep(TWO_THOUSAND);
             catch (InterruptedException e) 
                logger.error(e.getMessage(), e);
                Thread.currentThread().interrupt();
            
            logger.info("   ", Thread.currentThread().getName(), index);
        );
    
    executor.shutdown();

newScheduledThreadPool

  • newScheduledThreadPool(n):支持定时及周期性任务执行。
public static void useScheduledThreadPool() 
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
    executor.scheduleAtFixedRate(() -> 
        long start = System.currentTimeMillis();
        logger.info("scheduleAtFixedRate 开始执行时间:", DateFormat.getTimeInstance().format(new Date()));
        try 
            Thread.sleep(5000);
         catch (InterruptedException e) 
            logger.error(e.getMessage(), e);
        
        long end = System.currentTimeMillis();
        logger.info("scheduleAtFixedRate 执行花费时间=m", (end - start) / 1000);
        logger.info("scheduleAtFixedRate 执行完成时间:", DateFormat.getTimeInstance().format(new Date()));
        logger.info("======================================");
    , 1, 5, TimeUnit.SECONDS);

线程计数器CountDownLatch

  • CountDownLatch可以使一个获多个线程等待其他线程各自执行完毕后再执行。
  • CountDownLatch 定义了一个计数器,和一个阻塞队列, 当计数器的值递减为0之前,阻塞队列里面的线程处于挂起状态,当计数器递减到0时会唤醒阻塞队列所有线程,这里的计数器是一个标志,可以表示一个任务一个线程,也可以表示一个倒计时器,CountDownLatch可以解决那些一个或者多个线程在执行之前必须依赖于某些必要的前提业务先执行的场景。
public class CountDownLatchTest 

    private static final Logger logger = LoggerFactory以上是关于# Java 常用代码片段的主要内容,如果未能解决你的问题,请参考以下文章

MPI 中的屏障:如何实现屏障以使进程相互等待

# Java 常用代码片段

# Java 常用代码片段

Java 封装

Java 封装

Java 封装