Java 面试复习_3

2026年Java后端面试3天高效复习指南:从八股文到实战思维 Java后端开发作为企业级应用的核心技术栈,其知识体系涵盖语言基础、框架原理、分布式架构等多个层面。理解技术选型背后的设计思想,比如在MySQL与Redis之间根据数据一致性需求做出权衡,或基于业务场景设计微服务拆分方案,是工程师从“会用”到“精通”的关键跃迁。这种技术判断能力在面试中尤为重要,尤其是在云原生和分布式系统成为主流的技术趋势下。本文以2026年Java后端面试为例,结合高频八股文和实战场景,系统讲解如何通过3天时间快速构建技术脉络,重点覆盖容器化部署、分布式事务等热点问题,帮助求职者将知识点转 阅读详情


2019-5-19
作者:水不要鱼

(注:能力有限,如有说错,请指正!)

  • 创建线程的方式

  1. 继承 Thread 类,并重写 run() 方法,这种方式有局限性,由于 Java 中是单继承的,
    所以继承了 Thread 类就意味着不能再继承别的类了
  2. 实现 Runnable 接口,实现 run() 方法,这种方式不存在单继承的局限性,但是它没有返回值,
    所以如果执行的任务需要返回数据,就只能使用数据共享的方式来获得执行结果了
  3. 实现 Callable 接口,实现 call() 方法,这种方式需要先将 Callable 对象包装成 FutureTask 对象,
    因为 Thread 的构造器就是支持 Runnable 对象,但好处就是,它可以拿到返回值
class Test {
    // 继承 Thread 类
    static class Thread1 extends Thread {
        @Override
        public void run() {
            // 获取当前线程:this
            System.out.println("我是 " + this.getName());
        }
    }
    
    // 实现 Runnable 接口
    static class Thread2 implements Runnable {
        @Override
        public void run() {
            // 获取当前线程:Thread.currentThread()
            System.out.println("我是 " + Thread.currentThread().getName());
        }
    }
    
    // 实现 Callable 接口
    static class Thread3 implements Callable<Void> {
        @Override
        public Void call() throws Exception {
            // 获取当前线程:Thread.currentThread()
            System.out.println("我是 " + Thread.currentThread().getName());
            return null;
        }
    }
    
    public static void main(String[] args) throws Exception {
    
        new Thread1().start();
        new Thread(new Thread2()).start();
        
        // 注意这里需要将 Callable 包装成 FutureTask
        // 实际上,FutureTask 实现了 Runnable 接口,所以才能传给 Thread
        FutureTask task = new FutureTask<>(new Thread3());
        new Thread(task).start();
        
        // 获得返回值,这是阻塞方法,
        // 建议使用带等待时间的 get(long timeout, TimeUnit unit)
        task.get();
    }
}

扩展:线程池

我们知道线程的创建和销毁是需要消耗性能的,而且操作系统对于线程的数量一般都会有限制,
所以我们需要一种保障,它需要满足两点:1. 线程复用,减少创建和销毁的性能消耗;2. 限制线程数量,以免线程数量太多导致过多的线程上下文切换,甚至把操作系统搞崩。

这种保障就是线程池。从字面意思很好理解,就是一个装满线程的池子,需要的时候就从里面拿一个线程,
用完了就放回去,和共享有点像。JDK 中提供了一个线程池类:ThreadPoolExecutor,构造参数如下:

class ThreadPoolExecutor {
    public ThreadPoolExecutor(
            int corePoolSize, // 核心线程数
            int maximumPoolSize, // 最大线程数
            long keepAliveTime, // 线程空闲存活时间
            TimeUnit unit, // 存活时间单位
            BlockingQueue<Runnable> workQueue, // 任务缓冲队列
            ThreadFactory threadFactory, // 线程工厂
            RejectedExecutionHandler handler // 线程池不能再处理任务的时候,执行的拒绝策略
            ) {
        // 省略源码。。。
    }
}

线程池内部是这样工作的:

  1. 当线程池线程数量还没达到核心线程数的时候,每来一个任务,如果没有空闲线程可以执行的话,就创建一个新线程去执行任务
  2. 当线程池线程数量已经达到核心线程数的时候,再来任务,如果没有空闲线程可以执行的话,就将任务放入任务缓冲队列
  3. 线程池中的线程会不断从任务缓冲队列中取任务执行,这个队列是阻塞的,也就是拿不到任务的话,就会等待新任务的到来
  4. 当任务缓冲队列也被填满了,就会再次创建线程,这部分线程将被标记为非核心数量线程,因为它们是介于核心线程数和最大线程数之间的线程
  5. 最终,线程数量达到了最大线程数,整个线程池便进入忙碌状态,这时候提交任务,就会执行拒绝策略

从上面我们可以看到,如果最大线程数是 Integer.MAX_VALUE,拒绝策略也就不会被执行,
因为不存在线程池满的情况。如果队列是无界的,就有可能撑爆服务器内存。

我们再来仔细看看上面的一些参数:

  1. keepAliveTime,线程空闲存活时间

上面说过,如果线程池数量已经达到核心线程数了,再创建出来的线程就会被标记为非核心线程,
当这些被标记为非核心线程的线程空闲的时间达到了 keepAliveTime 之后,就会被回收销毁。

那核心线程有没有可能被销毁呢?有的,在这个类中有一个方法:void allowCoreThreadTimeOut(boolean value),
可以设置核心线程也会被超时回收,也就是说核心线程和非核心线程的待遇一样了,这点从源码中可以看到:

class ThreadPoolExecutor {
    /**
    * If false (default), core threads stay alive even when idle.
    * If true, core threads use keepAliveTime to time out waiting
    * for work.
    */
    private volatile boolean allowCoreThreadTimeOut;
}
  1. workQueue,任务缓冲队列

这个参数的类型是 BlockingQueue ,这是一个接口,而且带了泛型,也就是说最终放进队列的一定是 Runnable 对象,
另外,这是个 BlockingQueue 也就是阻塞队列。阻塞的意思就是当拿不到东西的时候就会等待,当放不进东西的时候也会等待。
这个接口有一些方法很有意思:

  • boolean add(E e):这个方法很霸道,一旦队列满了,添加元素失败,就会爆出 IllegalStateException 异常
  • boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException:
    如果添加失败,会等待特定的时间,时间到了还是添加不成功就会直接返回了,润物细无声,你甚至不知道它还在等你哈哈
  • E poll(long timeout, TimeUnit unit) throws InterruptedException:和 offer 类似,
    一段时间等不到就不等了,我猜它心里肯定是这么想的:老娘又不是没人要,哼,渣男!
  • void put(E e) throws InterruptedException:这个方法也很霸道,因为你仔细看的话会发现,它没有返回值!
    意思就是它只能成功,不能失败,所以返回值就没有意义了。保证成功的秘诀就是,死等,只要没有人中断,就等待。
  • E take() throws InterruptedException:和 put 类似,死等直到能拿到元素为止

在 JDK 中提供了很多的 BlockingQueue 实现类:

  • ArrayBlockingQueue:底层使用数组来实现,并且提供了容量限制,一定要给初始化容量,这个值将根据业务的量来定,
    开的太大会浪费内存,开的太小,很容易满,就会导致新创建线程甚至是执行拒绝策略

  • LinkedBlockingQueue:底层使用链表来实现,它提供了默认容量,大小为 Integer.MAX_VALUE,
    这意味着如果不指定大小,它将会消耗大量的内存,如果超过了机器的内存大小,就会导致内存溢出。所以在使用的时候,
    还是建议手动指定大小

  • SynchronousQueue:这是最诡异的一个队列,它的容量为 0,也就是你不能添加任何的元素进去,执行 offer 方法永远返回 false,执行 poll() 永远返回 null。从源码注释中,我发现了这样一段话:

Synchronous queues are similar to rendezvous channels used in CSP and Ada.

也就是说,这个队列是类似于 CSP 并发模型中的 channel 的,比如 Go 中的 channel。
在 Java 中,我搜索了一遍,发现除了 Executors 这些有用到它之外,还有 com.sun.webkit.network.SocketStreamHandle 这个类有用到,但也仅仅只是用来初始化线程池,没有拿来作 channel 使用。所以这个队列在 Java 中貌似就是空队列的存在

另外,这个队列支持公平和非公平,我们来看源码:

class SynchronousQueue {
    /**
    * Creates a {@code SynchronousQueue} with the specified fairness policy.
    *
    * @param fair if true, waiting threads contend in FIFO order for
    *        access; otherwise the order is unspecified.
    */
    public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
    }
}

很明显,当设置为公平时,就是 TransferQueue 对象,也就是 FIFO 的队列,反之,非公平就是 TransferStack 对象
在源码中我还发现一堆很有趣的东西:

class SynchronousQueue {
    /*
    * To cope with serialization strategy in the 1.5 version of
    * SynchronousQueue, we declare some unused classes and fields
    * that exist solely to enable serializability across versions.
    * These fields are never used, so are initialized only if this
    * object is ever serialized or deserialized.
    */
    
    @SuppressWarnings("serial")
    static class WaitQueue implements java.io.Serializable { }
    static class LifoWaitQueue extends WaitQueue {
        private static final long serialVersionUID = -3633113410248163686L;
    }
    static class FifoWaitQueue extends WaitQueue {
        private static final long serialVersionUID = -3623113410248163686L;
    }
    private ReentrantLock qlock;
    private WaitQueue waitingProducers;
    private WaitQueue waitingConsumers;
}

我跟踪使用的地方,发现只有两个地方有用到:

class SynchronousQueue {
    /**
    * Saves this queue to a stream (that is, serializes it).
    * @param s the stream
    * @throws java.io.IOException if an I/O error occurs
    */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        boolean fair = transferer instanceof TransferQueue;
        if (fair) {
            qlock = new ReentrantLock(true);
            waitingProducers = new FifoWaitQueue();
            waitingConsumers = new FifoWaitQueue();
        }
        else {
            qlock = new ReentrantLock();
            waitingProducers = new LifoWaitQueue();
            waitingConsumers = new LifoWaitQueue();
        }
        s.defaultWriteObject();
    }
    
    /**
    * Reconstitutes this queue from a stream (that is, deserializes it).
    * @param s the stream
    * @throws ClassNotFoundException if the class of a serialized object
    *         could not be found
    * @throws java.io.IOException if an I/O error occurs
    */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        if (waitingProducers instanceof FifoWaitQueue)
            transferer = new TransferQueue<E>();
        else
            transferer = new TransferStack<E>();
    }
}

换而言之,就是序列化的时候要用到,一个空队列居然也要序列化??搞不懂 Doug Lea 的想法,
或许这个队列还有其他很大的作用,只是我们还没有发现

  • PriorityBlockingQueue:优先队列,底层使用数组模拟的堆结构实现,
    和 java.util.PriorityQueue 的功能一样,只是它是阻塞的。可以指定初始化容量,而且内部还保存了一个 PriorityQueue 用于序列化,
    也就是在 writeObject 中将数据写入内部这个的 PriorityQueue,然后序列化这个 PriorityQueue,
    在 readObject 中从 PriorityQueue 中读取数据并初始化 PriorityBlockingQueue

  • DelayQueue:延迟队列,底层使用优先队列来排序时间,也就是说,当你向这个队列添加元素的时候,它会根据这个元素的延迟时间来升序排序,
    这样最先出队的就是延迟最低时间最短的那个元素了。那元素的延迟时间怎么设置?我们可以发现,这个类的定义是有泛型的:

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {}

这个泛型 E extends Delayed 就意味着入队的元素必须实现 java.util.concurrent.Delayed 接口,
进而实现 long getDelay(TimeUnit unit) 方法来设置元素的延迟时间。这个队列使用了 Leader-Follower 模式来减少等待的时间,
感兴趣的可以去搜相关内容

还有一个类和这个类很相似,那就是 java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue 队列,
但是这个队列没有直接使用优先队列,而是又重写了堆结构,同样要求元素实现 java.util.concurrent.Delayed 接口

  1. handler,拒绝策略

上面说过,当线程池满了的时候,就会执行拒绝策略。这个参数是 java.util.concurrent.RejectedExecutionHandler 接口,
里面有一个 void rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法,我们可以自己定义拒绝策略,
用于不同的业务需求。

比如说,你这个线程池的任务不允许有一丝的丢失,而线程池又不可能一直处理任务,
你就可以定义一个拒绝策略:

class NotRejectedExecutionHandler implements RejectedExecutionHandler {
    // 重试次数
    // 保存操作有可能失败,所以需要重试,但是不能一直重试,
    // 必须要有个重试次数限制,否则就会导致资源浪费
    private static final int RETRY_TIMES = 3;
    
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    // Runnable r: 被拒绝的任务对象
    // ThreadPoolExecutor executor: 当前执行任务的这个线程池
    
    // 场景假设:不允许丢失任何一个任务
    // 我们可以将任务对象持久化,比如保存在数据库中,
    // 之后由定时任务来从数据库取出任务执行
    int retryTimes = 0;
    while (!save(r)) {
        retryTimes++;
        if (retryTimes > RETRY_TIMES) {
            // 如果重试了三次都失败了,就需要采取应急措施
            notifyWorker(r);
            break;
        }
    }
    
    private boolean save(Runnable task) {
        // 数据库保存操作...
        return true;
    }
    
    private void notifyWorker(Runnable r) {
        // 日志记录,或者发邮件通知运维人员之类的...
        // 由于这已经是应急操作了,所以日志记录是必须的
        // 而且为了保证应急操作成功,最好执行一些失败率很低的操作
    }
}

上面只是举了一个例子,你还可以将任务保存在缓存系统或者消息队列中,这些都需要根据实际业务来定。
如果你没有指定这个参数,就会使用默认的拒绝策略,也就是直接抛异常:

class ThreadPoolExecutor {
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 threadFactory, defaultHandler);
        // 这里的 defaultHandler 就是下面的 AbortPolicy
    }
    
    /**
    * The default rejected execution handler
    */
    private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
    
    /**
    * A handler for rejected tasks that throws a
    * {@code RejectedExecutionException}.
    */
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
        * Creates an {@code AbortPolicy}.
        */
        public AbortPolicy() {}

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                          " rejected from " + e.toString());
        }
    }
}

除了上面的 AbortPolicy 默认拒绝策略之外,还有几个内置的拒绝策略:

  • CallerRunsPolicy:在调用者线程执行这个任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code CallerRunsPolicy}.
     */
    public CallerRunsPolicy() {}
    
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            // 直接执行这个 run 方法
            r.run();
        }
    }
}
  • DiscardOldestPolicy:丢掉最老的元素,空出位置执行这个被拒绝的任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardOldestPolicy} for the given executor.
     */
    public DiscardOldestPolicy() {}
    
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            // 将队列的第一个元素移除,空出位置来,然后再将任务加进去执行
            e.getQueue().poll();
            e.execute(r);
        }
    }
}
  • DiscardPolicy:这是最简单的策略了,就是直接拒绝,也不会抛出异常,
    就是很安静的抛弃掉任务,无声无息,悄悄地就走了
public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardPolicy}.
     */
    public DiscardPolicy() {}
    
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        // 啥也不干
    }
}
  • JDK 内置线程池

在 JDK 中提供了 Executors 工具类,里面有几个工厂方法,可以快速创建几种线程池:

  1. newCachedThreadPool(),这个线程池从某种程度上来说不能算是线程池,我们来看方法源码:
class Executors {
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(
                0, // 核心线程数
                Integer.MAX_VALUE, // 最大线程数
                60L, TimeUnit.SECONDS, // 非核心线程空闲 60 秒就被回收
                // 任务缓冲队列
                // 一旦达到核心线程数,这个队列又不接受元素,就会开始创建非核心线程
                new SynchronousQueue<Runnable>()
                // 默认的拒绝策略:AbortPolicy,也就是直接报异常
                );
    }
}

为什么我说这不能算是线程池?

它的核心线程数设置为 0,而任务缓冲队列又是 SynchronousQueue,
也就是说一旦有任务到来,就直接创建非核心线程。一旦每个任务的执行时间都超过 60 秒,就会导致一直创建新线程。
而由于创建的都是非核心线程,所以一旦空闲,又会被全部回收销毁。
这也就失去线程池的价值,资源控制和减少创建销毁性能消耗

那这个线程有什么意义吗?

如果你真的要说意义,那就是可以用来运行非常短小的任务,比如一个任务就几秒的运行时间,
由于 60 秒才会回收空闲线程,所以线程可以不断重用,这时候它还像个线程池

  1. newFixedThreadPool(int nThreads),固定线程数量的线程池,还是来看方法源码:
class Executors {
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(
                nThreads, // 核心线程数
                nThreads, // 最大线程数
                0L, TimeUnit.MILLISECONDS, // 非核心线程空闲立马被回收
                // 任务缓存队列
                // 使用了不指定大小的 LinkedBlockingQueue 就意味着队列长度是 Integer.MAX_VALUE,
                // 所有任务太多就会占用很多的内存,也就有可能将内存耗尽,导致服务器崩溃
                new LinkedBlockingQueue<Runnable>()
                // 默认的拒绝策略:AbortPolicy,也就是直接报异常
                );
    }
}

我们可以留意到这个线程池的设置,核心线程数和最大线程数是一样的,也就是说队列满了,线程池就满了,
就不会创建非核心线程,所以这时候 0L, TimeUnit.MILLISECONDS 的设置相当于失效

  1. newSingleThreadExecutor(),单线程的线程池,废话不多说,上源码:
class Executors {
    public static ExecutorService newSingleThreadExecutor() {
         return new FinalizableDelegatedExecutorService
             (new ThreadPoolExecutor(
                     1, // 核心线程数
                     1, // 最大线程数
                     0L, TimeUnit.MILLISECONDS, // 非核心线程空闲立马被回收
                     // 任务缓存队列
                     // 使用了不指定大小的 LinkedBlockingQueue 就意味着队列长度是 Integer.MAX_VALUE,
                     // 所有任务太多就会占用很多的内存,也就有可能将内存耗尽,导致服务器崩溃
                     new LinkedBlockingQueue<Runnable>())
                     // 默认的拒绝策略:AbortPolicy,也就是直接报异常
                     );
    }
}

你可以把它当成是 newFixedThreadPool(1)

  1. newScheduledThreadPool(int corePoolSize),定时任务线程池
class Executors {
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
}

// 可以看到 ScheduledThreadPoolExecutor 的父类是 ThreadPoolExecutor
class ScheduledThreadPoolExecutor extends ThreadPoolExecutor
      implements ScheduledExecutorService {
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        // 下面的代码其实就是创建 ThreadPoolExecutor
         super(
                 corePoolSize, // 核心线程数
                 Integer.MAX_VALUE, // 最大线程数
                 0, NANOSECONDS, // 非核心线程空闲立马被回收
                 // 任务缓存队列
                 // 与 DelayQueue 类似
                 // 要求元素必须实现 java.util.concurrent.Delayed 接口
                 new DelayedWorkQueue()
                 // 默认的拒绝策略:AbortPolicy,也就是直接报异常
                 );
    }
}

定时任务线程池,可以说是 ThreadPoolExecutor 的子类,其实内部使用的队列是延迟队列,
这就意味着如果元素延迟时间还没到的话,就会阻塞,从而达到定时的效果。

这个线程池还可以定时间隔执行任务,它的原理其实很奇妙。就是把一个任务正常执行,然后判断它是否需要重复执行,
如果需要就把延迟时间更新为下一次执行的时间,再放回队列,这样就实现了重复间隔执行的效果

  1. newWorkStealingPool(int parallelism),会偷任务来做的线程池
class Executors {
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool(parallelism,
                 ForkJoinPool.defaultForkJoinWorkerThreadFactory,
                 null, true);
    }
}

看了这么多内置线程池的源码,终于有一个是不一样的了。内部使用的是 ForkJoinPool 实现,
感兴趣的可以搜索来看

今天就到这里!晚安!
ESP32学习笔记06-UART 的485 通讯模式 通信方式选择UART 控制器支持多种通信模式,使用函数 uart_set_mode() 可以选择模式。选择特定模式后,UART 驱动程序将处理已连接 UART 设备的相应行为。例如,主机开始向 Tx FIFO 缓冲区写入数据时,UART 驱动程序会自动置位 RTS 管脚(逻辑 1);最后一位数据传输完成后,驱动程序就会取消置位 RTS 管脚(逻辑 0)。要使用此模式,软件。 阅读详情

相关推荐

形位公差标注的常见误区与优化策略

本文深入解析机械设计中形位公差标注的常见误区与优化策略,特别针对NX2406用户提供实用技巧。从标注冗余、基准选择到公差值设定等五大误区入手,结合工程图实例展示如何提升标注精度与效率,帮助工程师避免常见错误,优化设计流程,确保零件功能实现与制造可行性。

info6的博客 244

JAVA线程池

为什么要有线程池 当线程生存时间较短,且这种线程数量增多的时候,会反复创建销毁线程而增加大量开销。 创建线程池 ThreadPoolExecutor函数。 参数:(摘自LiuZh_) int corePoolSize =&gt; 该线程池中核心线程数最大值 核心线程: 线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过cor...

zhaowh1993的博客 259

S32K144 ADC硬件触发+DMA传输实战:从寄存器配置到数据采集全流程

本文详细解析了S32K144微控制器中ADC硬件触发与DMA传输的协同工作机制,提供了从寄存器配置到数据采集的全流程实战指南。通过PDB定时触发ADC转换,并利用DMA实现数据自动搬运,构建了高效、实时的汽车级数据采集系统,有效释放CPU资源,满足汽车电子应用的严苛要求。

weixin_29194693的博客 475

手写ThreadPoolExecutor线程池

很多人不推荐造轮子,我偏不。我造轮子又不是为了上生产环境,而是为了加深理解,有何不可?私以为造轮子几乎是最好的学习方式,甚至没有之一。不了解设计,就无法把握整体。没看过代码,就无法完善细节。另外,从创作者的角度来说,直接分析源码有时太困难了,代码太多,抽象层次太深。如果可以通过造轮子,把抽象层次减少一些,采用平铺直叙的方式呈现,那么读者理解起来也就更容易些。既然造轮子这么好,那就,拿来吧你。今天带大家造一个线程池。

smart_an的专栏 154

Neurocomputing 投稿指南

Generation Information:选择论文所属领域。上传附件(利益声明,手稿,摘要)审稿人偏好:可以选择期待的审稿人。

qq_41174671的博客 2万+

国产HDMI2.0芯片GSV2011怎么选?手把手教你用它设计音视频采集卡(附FPGA/海思对接指南)

本文详细解析国产HDMI2.0芯片GSV2011在音视频采集卡设计中的应用,涵盖芯片选型、硬件设计要点及与FPGA/海思平台的对接指南。GSV2011凭借4K@60Hz支持、音频提取嵌入功能和高集成度,成为音视频设备的核心选择,助力开发者快速实现高性能采集卡设计。

weixin_30181209的博客 332

Java线程池中的核心线程是如何被重复利用的?

真的!讲得太清楚了!https://blog.youkuaiyun.com/MingHuang2017/article/details/79571529 真的是解惑了   本文所说的“核心线程”、“非核心线程”是一个虚拟的概念,是为了方便描述而虚拟出来的概念,在代码中并没有哪个线程被标记为“核心线程”或“非核心线程”,所有线程都是一样的,只是当线程池中的线程多于指定的核心线程数量时,会将多出...

weixin_30318645的博客 306

ANSYS 12.1避坑全记录:当Win7+VMware14遇到FLEXlm报错时的自救指南

本文详细介绍了在Windows 7和VMware14环境下安装和运行ANSYS 12.1时遇到的FLEXlm报错问题及其解决方案。通过虚拟机技术隔离时间同步问题,提供从环境配置到许可证管理的完整指南,帮助用户稳定运行这一老旧版本的工程仿真软件。

tt34567的博客 644

SynchronousQueue解析上-TransferStack

Queue接口定义:[url]http://donald-draper.iteye.com/blog/2363491[/url] AbstractQueue简介:[url]http://donald-draper.iteye.com/blog/2363608[/url] ConcurrentLinkedQueue解析:[url]http://donald-draper.iteye.com/bl...

Donald_Draper 385

Java 类与对象 -- Java 语言的类与对象、构造器、static、final、包和 JAR

本篇文章我们将深入了解 Java 语言中的类与对象,探讨构造器、`static`、`final`、包和 JAR 文件。这些概念是面向对象编程的核心,对于理解和掌握 Java 至关重要。

栗筝i的博客 5034

【思博伦】史上最详细Spirent TestCenter测试仪使用教程精讲(一)!图解超赞超详细!!!

3. 在弹出的界面中,找到菜单栏中的“Connect/Create”,选择下拉框中的“Connect to Physical/Visual Chassis”,在弹出的对话框中输入思博伦测试仪的IP地址:192.168.6.244,点击“OK”;说明:目前我们只需要使用到Raw Stream Block,不需要用到Bound Stream Block。说明:如果要使用100G模式,由于硬件限制,必须连续3个面板端口同时配置为100G使用。打开安装包,并按照提示按照即可。

风云说通信 6478

Java后端面试3天高效复习:核心考点与实战解析

Java作为企业级应用开发的核心语言,其技术体系涵盖从基础语法到分布式架构的完整知识栈。理解Java虚拟机内存模型、并发编程原理等底层机制,对于构建高性能、高可用的后端系统具有重要价值。在实际应用中,Spring框架的IoC容器和AOP编程模型大大提升了开发效率,而MySQL索引优化和Redis缓存策略则是保障系统性能的关键技术。随着微服务架构的普及,系统设计能力成为面试中的重要考察点。本文基于HashMap底层原理和线程池工作机制等高频考点,结合2026年最新面试趋势,为Java后端开发者提供一套可落地的

weixin_33827590的博客 465

OpenCASCADE完整教程专栏完整目录

OpenCASCADE完整教程专栏完整目录

希望我的博客,能帮上你解决学习中工作中所遇到的问题 9695

Java八股文智能复习系统:基于SmallThinker-3B-Preview的面试刷题伴侣

本文介绍了基于星图GPU平台,可自动化部署SmallThinker-3B-Preview镜像,快速搭建Java八股文智能复习系统。该系统能作为面试刷题伴侣,通过智能对话实现精准答题、深度追问与模拟面试,帮助开发者高效复习JVM、并发、Spring等核心知识点,提升面试准备效率。

weixin_35753431的博客 298

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

java面试八股文复习3

集合框架 List(线性结构) public interface List<E> extends Collection<E> {} 即有序的集合(也可以称作序列)。该接口的使用者可以精确地将控制每个元素在list中的插入位置。用户可以通过integer索引(即list中的位置)访问元素,并在list中搜索元素。 和集合(set)不同,list通常允许重复元素。即若list中存在a1,a2且a1.equals(a2)这在list中是被允许的。除了在set接口中有指定的规则,list接

weixin_45038271的博客 339

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Java面试复习 Day 3

区域线程归属核心存储内容是否参与GC常见异常‌程序计数器‌私有指令地址否无‌虚拟机栈‌私有栈帧、局部变量否‌本地方法栈‌私有Native方法状态否‌堆‌共享对象实例、数组‌是 (核心)‌OOM‌方法区‌共享类元数据、常量、静态变量‌是 (少量)‌OOM口诀:‌对象存堆,局部变量存栈,类和静态放方法区,行号记在计数器,native方法走本地栈‌。‌‌。

lotus_csdn888的博客 179

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Java面试复习 2021/3/22

子类,方法方法同步 如果父类中的某个方法使用了synchronized关键字,而子类中也覆盖了这个方法, 默认情况下子类中的这个方法并不是同步的,必须显示的在子类的这个方法中加上synchronized关键字才可。 当然,也可以在子类中调用父类中相应的方法,这样虽然子类中的方法并不是同步的,但子类调用了父类中的同步方法,也就相当子类方法也同步了。 接口中的修饰的方法 接口中的方法默认都是public static final,这是JAVA8的规定。 构造函数只能被调用,不能被继承。 子类默..

Shapeofyou的博客 236

Java八股文智能复习:SmallThinker-3B-Preview模拟面试与深度解析

本文介绍了如何利用星图GPU平台,一键自动化部署SmallThinker-3B-Preview镜像,以构建一个智能的Java面试复习助手。该模型能够模拟真实面试场景,通过深度追问和主动出题,帮助开发者深入理解JVM、集合框架等核心八股文知识点,实现高效的互动式学习与查漏补缺。

weixin_36328210的博客 28

Java面试复习总结3——string和包装类

目录 String基础 Java String 类 创建字符串 StringDemo.java 文件代码: String基本用法 创建String对象的常用方法 String中常用的方法,用法如图所示,具体问度娘 三个方法的使用: lenth() substring() charAt() 字符串与byte数组间的相互转换 ==运算符和equals之间的区别: 字符串的不可变性...

Slayer_Zhao的博客 787

Java面试 2021-3-21复习

JAVA的运算符 算数运算符、关系运算符、逻辑运算符、位运算符 算数运算符(9):+ - * / % ++ -- 关系运算符(6):== != > >= < <= 逻辑运算符(6):&& || ! ^ &(按位与) | 位运算符(7):& | ~ ^ >> << >>>; 注意: 实际含义不同: “||”:如果左边计算后的操作数为true,右边则...

Shapeofyou的博客 122

Java面试复习(3)之IO流

IO流(Input Output)

i_nclude的博客 315

Java后端面试3天高效复习指南:核心知识点与实战技巧

Java作为企业级应用开发的核心语言,其技术生态涵盖从基础语法到分布式系统设计的广泛领域。理解Java虚拟机(JVM)的内存管理机制和垃圾回收原理,是优化应用性能的关键;而并发编程中的线程池配置与锁机制,则直接影响高并发场景下的系统稳定性。结合MySQL索引优化与Redis缓存技术,能够有效提升数据读写效率,解决缓存穿透、击穿等典型问题。Spring框架通过IOC和AOP实现了组件解耦与功能增强,而Spring Boot的自动配置机制进一步简化了企业级应用的开发部署。这些技术共同支撑了电商秒杀、实时数据处理

weixin_30938149的博客 539

2026年Java后端面试核心考点与3天高效复习策略

Java并发编程是后端开发的核心技术之一,其原理基于多线程协同处理任务以提升系统吞吐量。通过理解线程生命周期、锁机制和内存模型,开发者能够编写出高效且线程安全的代码。这项技术的价值在于充分利用多核CPU资源,应对高并发场景下的性能挑战。在实际应用中,Java并发广泛用于电商秒杀、实时数据处理等业务场景。本文结合线程池和synchronized等热词,深入探讨面试中常见的并发问题解决方案,帮助求职者快速掌握核心考点。

weixin_30915275的博客 307

Java面试 2021/3/20复习

1.File类对象代表:一个文件或一个文件目录。Java程序表示一个文件或目录,必须有个File对象。但有File对象不一定有真实的文件或目录存在。 2.File类不能进行对文件进行的输入和输出操作(使用IO流才行)。 3. ...

Shapeofyou的博客 104

Java后端面试3天高效复习指南:从核心考点到实战技巧

Java作为企业级应用开发的核心语言,其底层原理和工程实践是后端开发者的必备基础。理解Java集合框架的线程安全机制、JVM内存模型和垃圾回收原理,能够帮助开发者编写高性能、可扩展的应用程序。在分布式系统中,MySQL索引优化和Redis缓存技术尤为重要,它们直接影响系统的响应速度和数据一致性。通过掌握这些核心技术,开发者可以应对高并发场景下的数据存储与缓存挑战,例如电商秒杀系统的库存扣减和缓存穿透问题。本文基于Java并发编程和Redis实战经验,提供了一套3天高效复习方案,帮助面试者快速梳理技术脉络,将

weixin_33875564的博客 397

挑战Java面试题复习第3天,无人扶我青云志

无人扶我青云志,我自踏雪至山巅

专注编程和人工智能! 791
上一篇: Java 面试复习_2
下一篇: Java 面试复习_4
水不要鱼
博客等级 码龄7年 7粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值