Java基础知识及面试题9

Java中的线程池通过Executor框架实现,核心类为ThreadPoolExecutor,涉及核心线程数、最大线程数、阻塞队列和任务拒绝策略。AQS(AbstractQueuedSynchronizer)是Java并发基础框架,用于实现阻塞锁和同步器,支持独占模式和共享模式。同步锁是多线程同步的关键,包括互斥锁、读写锁等,用于保证共享资源的访问一致性。
摘要由CSDN通过智能技术生成

1、Java 中的线程池是如何实现的?

Java中的线程池是通过Executor框架实现的。一般采用ThreadPoolExecutor实现。
(1)创建线程池: 创建一个 ThreadPoolExecutor 对象,并指定核心线程数、最大线程数、空闲线程存活时间、阻塞队列和线程工厂等参数。

(2)提交任务: 使用 submit() 或 execute() 方法将任务提交到线程池中。如果线程池中有空闲线程,任务会被分配给其中一个线程执行。如果没有可用的空闲线程,任务会被放入阻塞队列中等待。

(3)执行任务: 当线程池中有空闲线程时,会从阻塞队列中取出任务并分配给线程执行。线程执行完任务后会重新进入线程池中等待下一个任务。

(4)处理任务拒绝策略: 当线程池无法接受新任务时,会触发任务拒绝策略,处理方式包括抛出异常、直接丢弃任务、阻塞等待或者让调用者自己执行任务。

(5)关闭线程池:使用 shutdown() 或 shutdownNow() 方法关闭线程池。shutdown() 方法会等待线程池中的任务全部执行完毕后关闭线程池,而 shutdownNow() 方法会立即关闭线程池,并尝试终止正在执行的任务。

2、什么是AQS?

AQS 全称为 AbstractQueuedSynchronizer,是 Java 并发包中用于实现同步器的基础框架。它提供了一种实现阻塞锁和相关同步器的基础设施,并且在 Java 并发包中有广泛应用,如 ReentrantLock、CountDownLatch、Semaphore 等。

AQS 是通过一个双向队列(FIFO) 来管理等待线程的,队列中的节点表示等待锁的线程,锁的拥有者是队列中的第一个节点。当锁被释放时,AQS 会唤醒等待队列中的下一个节点来获取锁。

AQS核心思想是将同步状态抽象成一个整数值,并且使用 CAS 操作来修改同步状态的值,实现多线程的互斥和协作。具体来说,AQS 提供了 acquire() 和 release() 方法,用于获取锁和释放锁,并且支持可重入锁和条件变量等特性。

3、AQS 对资源的共享方式?

**(1)独占模式(Exclusive Mode):**在独占模式下,只有一个线程能够获取锁,其他线程必须等待该线程释放锁才能获取。这种方式适用于需要对共享资源进行修改的情况。

**(2)共享模式(Shared Mode):**在共享模式下,多个线程可以同时获取同一个锁,但是不能同时修改共享资源。这种方式适用于需要对共享资源进行读取的情况。

**(3)混合模式(Mixed Mode):**混合模式可以同时支持独占和共享两种模式。这种方式适用于同时需要读取和修改共享资源的情况。

4、什么是锁?

在多线程编程中,锁是用于控制对共享资源访问的同步机制。当多个线程同时访问共享资源时,可能会出现数据竞争(Data Race)的问题,导致程序出现错误或者崩溃。为了避免这种情况发生,需要使用锁来协调线程之间的访问,保证共享资源的正确性和一致性。

5、什么是同步锁?

同步锁(Synchronization Lock),也称为互斥锁(Mutual Exclusion Lock),是一种用于同步多个线程对共享资源的访问的机制。同步锁可以确保同一时间只有一个线程可以访问共享资源,其他线程必须等待该线程释放锁之后才能继续访问共享资源,避免了数据竞争问题的发生。

常见的同步锁有互斥锁、读写锁、信号量等。不同类型的同步锁适用于不同的场景,例如:

(1)互斥锁(Mutex):适用于需要独占共享资源的场景,同一时间只有一个线程可以访问共享资源。

(2)读写锁(Read-Write Lock):适用于读多写少的场景,允许多个线程同时读取共享资源,但是只有一个线程可以进行写操作。

(3)信号量(Semaphore):适用于控制并发访问数量的场景,可以限制同时访问某个共享资源的线程数。

同步锁是保证多线程程序正确运行的重要手段,合理使用同步锁可以避免多线程程序中出现的各种问题。

6、线程的run()和start()有什么区别?

(1)run()方法是线程的核心执行方法,其中包含了线程要执行的具体任务代码,当线程调用run()方法时,它会在当前线程上运行,不会创建新的线程。因此,直接调用run()方法并不会启动新的线程,只会在当前线程上执行run()方法中的代码。

(2)start()方法是启动一个新线程的方法,当调用start()方法时,会创建一个新的线程,并在新的线程上执行run()方法中的代码。因此,只有通过调用start()方法才能启动一个新的线程。

总结来说,run()方法是线程的任务执行方法,start()方法是启动线程的方法。直接调用run()方法不会启动新的线程,而是在当前线程上执行run()方法中的代码,这种方式没有并发效果;而通过调用start()方法可以启动新的线程,在新的线程上并发执行run()方法中的代码,从而实现并发的效果。

需要注意的是,在一个线程对象中,start()方法只能调用一次,如果多次调用会抛出IllegalThreadStateException异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值