# 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
:具有优先级的无限阻塞队列。
拒绝策略
-
当提交的任务数大于队列和最大线程数的时候就会触发线程池的拒绝策略。
-
AbortPolicy
:ThreadPoolExecutor
中默认的拒绝策略就是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 常用代码片段的主要内容,如果未能解决你的问题,请参考以下文章