应届生Java面试50题线程篇(含解析)
-
什么是线程?
答:线程是操作系统能够进行运算调度的最小单位,是程序执行流的最小单元。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。
-
创建线程的方式有哪些?各自的优缺点是什么?
- 继承 Thread 类:继承 Thread 类并重写 run() 方法来实现多线程。优点是简单易用,缺点是无法继承其他类,会破坏程序的封装性,而且无法共享代码。
- 实现 Runnable 接口:实现 Runnable 接口并实现 run() 方法来实现多线程。优点是避免了继承的局限性,同时也可以实现资源的共享,缺点是需要创建 Thread 对象并传入 Runnable 实例。
- 实现 Callable 接口:实现 Callable 接口并实现 call() 方法来实现多线程。与 Runnable 接口相比,Callable 接口可以返回一个值,还可以抛出异常。缺点是需要创建 FutureTask 对象并将其传入 Thread 对象才能启动线程。
选择不同的方式创建线程要根据实际需求和场景来决定。一般来说,推荐使用实现 Runnable 接口的方式,因为这种方式避免了继承的局限性,还可以实现资源的共享;如果需要返回值或抛出异常,可以考虑使用实现 Callable 接口的方式;继承 Thread 类的方式可以用于创建简单的线程,但不够灵活,容易破坏程序的封装性,不建议使用。
-
启动线程为什么是用start()方法,而不是直接用run方法?
start()方法会在新的线程中执行任务,而直接调用run()方法只是在当前线程中执行任务,不会创建新的线程。
-
线程的生命周期有哪些阶段?
答:Java中的线程有5种状态:新建状态、就绪状态、运行状态、阻塞状态和终止状态。新建状态是指线程对象被创建但还没有调用start()方法;就绪状态是指线程调用了start()方法,但是没有分配到CPU资源,等待操作系统进行调度;运行状态是指线程正在执行run()方法;阻塞状态是指线程因为某些原因无法执行,例如调用了sleep()方法或者被阻塞在I/O操作中;终止状态是指线程执行完了run()方法或者因为异常等原因退出了。
-
什么是线程的阻塞和非阻塞?Java中如何实现线程的阻塞和非阻塞?
答:线程的阻塞是指线程在执行过程中,等待某个条件满足或者等待某个操作完成时被挂起的状态;线程的非阻塞是指线程在执行过程中,不会被挂起等待,可以继续执行其他任务。可以使用wait()、sleep()、join()等方法实现线程的阻塞,使用yield()方法实现线程的非阻塞。
-
sleep()和wait()的区别是什么?
答:sleep()和wait()都可以让线程暂停执行一段时间,但是它们的用法和作用不同。sleep()方法是Thread类中的静态方法,调用该方法可以让当前线程休眠一定的时间,期间不会释放锁,线程状态不会改变。wait()方法是Object类中的实例方法,调用该方法会使当前线程释放锁,并进入等待状态,直到其他线程调用notify()或notifyAll()方法唤醒它。wait()方法只能在同步代码块中使用。
-
如何实现线程间的通信?
答:线程间的通信可以通过wait()、notify()、notifyAll()方法来实现。其中,wait()方法可以使当前线程等待,直到其他线程调用notify()或notifyAll()方法唤醒它;notify()方法可以唤醒一个等待该对象锁的线程;notifyAll()方法可以唤醒所有等待该对象锁的线程。线程间还可以通过共享变量来进行通信,需要使用synchronized关键字保证共享变量的访问线程安全。
-
什么是wait()和notify()方法?如何使用wait()和notify()方法?
答:wait()和notify()方法是Java中用于实现线程间通信的方法,wait()方法可以使线程进入等待状态并释放锁,notify()方法可以唤醒一个等待中的线程并让它重新获取锁。wait()和notify()方法必须在同步块中使用,并且在调用wait()方法前必须获得锁对象的监视器。
-
什么是线程的调度算法?Java使用哪种线程调度算法?
答:线程的调度算法是指操作系统通过一定的策略选择要执行的线程。Java使用抢占式的优先级调度算法,每个线程都有一个优先级,优先级高的线程优先执行。同时,Java还引入了时间片轮转算法,每个线程被分配一个时间片,当时间片用完后,线程被挂起,等待下一轮调度。
-
什么是线程的中断?如何实现线程的中断?
答:线程的中断是指向线程发送一个中断信号,线程可以根据这个信号进行相应的操作。可以通过Thread类的interrupt()方法向线程发送中断信号,在线程的run()方法中可以使用isInterrupted()方法检查线程是否被中断,如果被中断则抛出InterruptedException异常,如果没有被中断则继续执行。
-
什么是线程死亡?Java中如何判断线程是否死亡?
答:线程死亡是指线程执行完毕或发生异常而终止运行的状态。可以使用isAlive()方法来判断线程是否死亡。
-
什么是守护线程?如何创建守护线程?
答:守护线程是指在程序运行过程中在后台提供服务的线程,是一种特殊的线程,它的生命周期和进程生命周期相同,并且只有在进程中存在非守护线程时才会运行。当所有非守护线程结束时,守护线程也会自动结束。可以通过Thread类的setDaemon()方法将一个线程设置为守护线程,例如:thread.setDaemon(true)。
-
什么是LockSupport类?Java中如何使用LockSupport类?
答:LockSupport类是一个线程阻塞工具类,可以实现线程的阻塞和唤醒操作。可以使用park()方法阻塞线程,使用unpark()方法唤醒线程。
-
什么是线程上下文切换?如何减少线程上下文切换的开销?
答:线程上下文切换是指在多线程并发执行时,由于CPU需要切换线程执行,需要将当前线程的状态保存下来,然后加载另一个线程的状态。会涉及到CPU寄存器、线程堆栈、程序计数器等上下文信息的保存和恢复。线程上下文切换的开销比较大,可以采取以下措施减少上下文切换的开销:尽量避免线程间的互斥和同步;采用CAS算法等非阻塞算法;采用协程等轻量级线程模型;减少线程的数量;使用线程池;减少锁的持有时间等。
-
什么是线程死锁?如何避免死锁?
答:线程死锁是指两个或多个线程相互等待对方释放资源而无法继续执行的状态。避免死锁的方法有:避免嵌套锁,尽量保持锁的持有时间短;避免多个线程同时获取多个锁,可以按照相同的顺序获取锁;使用tryLock()方法尝试获取锁,如果获取失败则立即释放已经获得的锁,避免线程长时间等待。设置超时时间等。
-
什么是线程的优先级?如何设置线程的优先级?
答:线程的优先级是指线程被调度的优先级,高优先级的线程会被更频繁地调度执行。可以通过Thread类的setPriority()方法来设置线程的优先级,优先级范围为1到10,默认为5。注意,优先级高的线程并不一定会比优先级低的线程先执行完毕。
-
什么是线程局部变量?如何使用线程局部变量?
答:线程局部变量是指只能被当前线程访问和修改的变量,可以使用ThreadLocal类来实现线程局部变量。每个线程都有自己的ThreadLocal对象,并且每个ThreadLocal对象只能保存一个值,通过get()方法和set()方法来访问和修改线程局部变量的值。
-
什么是同步和异步?Java中如何实现同步和异步?
答:同步和异步是指线程之间的调用方式,同步是指调用方会等待方法返回后再继续执行,异步是指调用方不会等待方法返回,而是通过回调等方式获得结果。可以使用synchronized关键字、Lock接口、Future接口等方式来实现同步和异步。
-
什么是原子操作?Java中如何保证原子操作?
答:原子操作是指不可被中断的一个或一系列操作,要么全部执行成功,要么全部执行失败,不会存在部分执行成功的情况。可以使用synchronized关键字、Lock接口、Atomic类等方式来保证原子操作。
-
什么是自旋?
自旋是一种在并发编程中常用的技术,它的主要思想是在获取锁失败时不立即阻塞等待,而是通过循环不断地尝试获取锁,直到获取到为止。
在Java中,自旋是通过在代码中使用synchronized关键字或者Lock接口的实现类来实现的。当一个线程尝试获取锁时,如果发现锁已经被其他线程占用,就会进入自旋状态,不断重试获取锁,直到获取到为止。
自旋的好处在于可以避免线程频繁地进入阻塞状态,从而减少线程上下文切换的开销,提高程序的运行效率。不过,自旋也有一定的缺点,如果自旋的时间过长,会浪费CPU资源。因此,使用自旋时需要权衡自旋的时间和获取锁的概率,以达到最优的性能表现。
-
synchronized关键字的作用是什么?
答:synchronized是Java中用来实现线程同步的关键字。使用synchronized修饰的代码块或者方法,在同一时刻只能被一个线程执行,其他线程需要等待当前线程执行完成后才能获取锁进入代码块或方法。synchronized可以避免多个线程同时修改共享变量造成的数据不一致问题。
-
什么是volatile关键字?有什么作用?
答:volatile关键字用于修饰变量,可以保证变量的可见性和禁止指令重排序优化。可以使用volatile关键字来确保多个线程之间对变量的修改是可见的,避免出现线程安全问题。
-
什么是线程安全?如何实现线程安全?
答:线程安全指多线程并发访问共享资源时,不会出现数据冲突或不一致的情况。实现线程安全的方法有:使用synchronized关键字保证访问共享资源的原子性和可见性;使用volatile关键字保证共享变量的可见性;使用线程安全的数据结构和类;使用ThreadLocal来保证线程本地变量的线程安全性。
-
怎么理解单例模式的线程安全性?
单例模式是一种创建型设计模式,其主要目的是确保在应用程序的整个生命周期内只存在一个实例对象。单例模式的线程安全性主要指在多线程环境下,单例对象的创建和访问不会出现线程安全问题。
在单例模式的实现中,如果使用饿汉式单例模式,即在类加载时就已经创建好了单例对象,那么其线程安全性是比较好的,因为在多线程环境下,类加载是线程安全的,每个线程只会执行一次类加载过程,因此只会创建一个单例对象。
但如果使用懒汉式单例模式,即在第一次访问单例对象时才进行创建操作,那么就需要考虑线程安全性了。在多线程环境下,如果多个线程同时访问单例对象,就有可能导致多次创建实例的情况发生。
-
什么是ThreadLocalRandom类?Java中如何使用ThreadLocalRandom类?
答:ThreadLocalRandom类是一个线程安全的随机数生成器,可以在多线程并发执行时避免竞争条件。可以使用ThreadLocalRandom类的静态方法来获取随机数。
-
什么是线程的可见性?如何保证线程的可见性?
答:线程的可见性是指在多线程环境下,一个线程对共享变量的修改可以被其他线程及时地看到。可以通过volatile关键字保证线程的可见性,volatile关键字可以保证一个变量的写操作对其他线程的读操作可见。
-
什么是并发?Java中有哪些并发编程的技术?
答:并发是指多个任务可以在同一时间段内同时执行的能力,Java中有多种并发编程的技术,包括线程池、同步机制、原子变量、并发集合等。
-
并发和并行的区别?
答:并发指的是多个任务在同一时间段内交替执行,由于时间片轮转等机制的作用,使得它们在宏观上具有同时执行的效果。在单核处理器的情况下,多个任务会通过时间片轮转来实现并发,而在多核处理器的情况下,多个任务可以真正地同时执行。
并行则指的是多个任务同时执行。在单核处理器上,无法实现真正的并行,只能通过多进程或者多线程的方式来实现伪并行,而在多核处理器上,多个任务可以真正地同时执行。
-
什么是线程池?有哪些优点?
答:线程池是一种线程管理机制,它可以创建一组线程并管理它们的执行,从而实现线程的复用,避免了线程创建和销毁的开销。可以使用Java的Executor框架来创建和管理线程池,例如:ThreadPoolExecutor类可以设置线程池的大小、线程池的工作队列、线程池的拒绝策略等参数。线程池的优点有:减少了线程的创建和销毁开销,提高了系统的响应速度;提高了线程的可管理性和可维护性;控制了并发线程的数量,避免系统资源被耗尽;提高了任务的处理效率。
-
如何创建线程池?
答:可以使用Java中的Executor框架来创建线程池,Executor框架提供了一些静态工厂方法来创建线程池,例如:newCachedThreadPool()、newFixedThreadPool()、newSingleThreadExecutor()等。其中,newCachedThreadPool()方法可以创建一个可以根据需要创建新线程的线程池;newFixedThreadPool()方法可以创建一个固定大小的线程池;newSingleThreadExecutor()方法可以创建一个只有一个线程的线程池。
-
线程池的核心参数有哪些?分别代表什么含义?
- corePoolSize:线程池中的核心线程数。当提交任务时,如果线程池中的线程数小于 corePoolSize,就会创建新的线程来处理任务,即使其他线程处于空闲状态。
- maximumPoolSize:线程池中最大的线程数。当提交的任务数大于 corePoolSize 并且工作队列已满时,线程池会创建新的线程来处理任务,直到线程数达到 maximumPoolSize。
- keepAliveTime:线程池中空闲线程的存活时间。当线程池中的线程数大于 corePoolSize 时,如果空闲线程的数量超过了 keepAliveTime 所设置的时间,就会被回收,直到线程数不大于 corePoolSize。
- workQueue:任务队列。用于存放还没有被执行的任务。当线程池中的线程数达到 corePoolSize 时,新提交的任务会被存储在这个队列中,直到队列已满。
- threadFactory:线程工厂。用于创建新的线程。
- handler:饱和策略。当线程池中的线程数达到 maximumPoolSize 并且队列已满时,用于处理新提交的任务。Java 中提供了四种饱和策略:AbortPolicy(抛出异常)、CallerRunsPolicy(由提交任务的线程来执行任务)、DiscardOldestPolicy(丢弃队列中最老的任务)和DiscardPolicy(丢弃当前的任务)。
-
线程池的工作流程是怎么的?
- 当线程池被创建时,会创建一定数量的线程(corePoolSize)并将它们置于等待任务的状态。
- 当有任务提交到线程池时,线程池会首先判断是否已经达到了最大线程数(maximumPoolSize)。如果没有达到最大线程数,则线程池会尝试创建新的线程来执行任务。否则,线程池会将任务加入任务队列(workQueue)中等待处理。
- 当线程池中的线程被空闲下来时,它们会尝试从任务队列中获取任务进行处理。如果任务队列为空,则线程会等待一段时间(keepAliveTime),如果等待时间超过了设定的时间,则线程将被回收。
- 当线程池被关闭时,线程池将不再接受新的任务。此时,线程池会等待所有任务都执行完毕,然后将所有的线程回收。
-
线程池的拒绝策略有哪些?
1.AbortPolicy(默认)
当线程池无法接受新任务时,抛出RejectedExecutionException异常。
示例代码:
codeExecutorService executorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1)); executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
2.CallerRunsPolicy
当线程池无法接受新任务时,由提交任务的线程来执行这个任务。
示例代码:
codeExecutorService executorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1)); executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
3.DiscardOldestPolicy
当线程池无法接受新任务时,丢弃队列中最旧的任务,然后将新任务加入队列。
示例代码:
codeExecutorService executorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1)); executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
4.DiscardPolicy
当线程池无法接受新任务时,直接丢弃该任务,不做任何处理。
示例代码:
codeExecutorService executorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1)); executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
以上是Java线程池提供的标准拒绝策略。除此之外,用户还可以自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可。
-
线程池提交任务的execute()和submit()方法有什么区别?
1.返回值类型不同
execute()方法返回void,而submit()方法返回Future对象,可以通过Future对象获取任务的执行结果。
2.参数类型不同
execute()方法接收Runnable对象作为参数,而submit()方法接收Callable或Runnable对象作为参数。Callable对象比Runnable对象多了一个返回值。
3.异常处理方式不同
execute()方法在执行任务时,如果抛出异常,会直接抛出,导致线程终止。而submit()方法在执行任务时,如果抛出异常,则会将异常封装在Future对象中返回,不会影响线程的继续执行。
4.任务执行顺序不同
execute()方法提交的任务按照提交的顺序执行,而submit()方法提交的任务是异步执行的,执行顺序可能与提交顺序不一致。
5.取消任务的方式不同
submit()方法提交的任务可以通过Future对象的cancel()方法取消,而execute()方法提交的任务无法取消。
-
线程池怎么关闭?
1.调用shutdown()方法
调用线程池的shutdown()方法会启动线程池的关闭过程。该方法会停止接收新任务,等待所有已提交的任务执行完成,然后关闭线程池。
示例代码:
codeExecutorService executorService = Executors.newFixedThreadPool(5); // 提交任务 executorService.submit(new Task()); // 关闭线程池 executorService.shutdown();
2.调用shutdownNow()方法
调用线程池的shutdownNow()方法会启动线程池的立即关闭过程。该方法会停止接收新任务,尝试中断所有正在执行的任务,并返回所有未执行的任务列表。
示例代码:
codeExecutorService executorService = Executors.newFixedThreadPool(5); // 提交任务 executorService.submit(new Task()); // 关闭线程池 List<Runnable> undoneTasks = executorService.shutdownNow();
-
什么是线程组?如何使用线程组?
答:线程组是一组线程的集合,可以使用ThreadGroup类来创建和管理线程组。可以通过ThreadGroup类的构造方法来创建线程组,例如:ThreadGroup group = new ThreadGroup(“myGroup”);可以将线程添加到线程组中,例如:new Thread(group, “thread1”)。线程组可以提供统一的异常处理、优先级调整、暂停和恢复等功能。
-
线程之间有哪些协作方式?
- 等待通知机制:线程通过调用
wait()
方法释放锁,并等待其他线程调用notify()
或notifyAll()
方法来唤醒自己,从而实现线程之间的协作。 - 信号量(Semaphore):Semaphore 为多个线程提供了一个共享的信号量,线程可以通过 acquire() 方法来获取信号量,通过 release() 方法来释放信号量。当信号量的值为 0 时,acquire() 方法会阻塞线程。
- CountDownLatch:CountDownLatch 是一个计数器,线程在等待前可以将计数器的值设置为一个正整数,当计数器减到 0 时,所有等待的线程都会被唤醒。
- CyclicBarrier:CyclicBarrier 可以让一组线程在达到某个屏障点时停止执行,当所有线程都到达屏障点后,它们会被释放并继续执行。
- Phaser:Phaser 是 JDK7 中引入的一个新的同步工具,它可以协调多个线程在一起执行任务,Phaser 可以被视为一个可以重复使用的 CyclicBarrier。
- Exchanger:Exchanger 可以让两个线程之间交换数据,当两个线程都调用 exchanger() 方法时,它们会被阻塞,直到两个线程都到达 exchanger() 方法后,它们会交换数据并继续执行。
- Lock 和 Condition:Lock 和 Condition 是 JDK5 中引入的新特性,Lock 提供了与 synchronized 关键字类似的功能,Condition 可以在等待某些条件满足时挂起线程,并在条件满足时唤醒线程。
- 等待通知机制:线程通过调用
-
什么是信号量?如何使用信号量实现线程同步?
答:信号量是一种用于线程同步的机制,可以通过Semaphore类来实现。可以通过调用Semaphore类的acquire()方法获取信号量,当信号量可用时,acquire()方法会返回;当信号量不可用时,acquire()方法会阻塞当前线程,直到有一个信号量可用为止。
-
什么是Semaphore信号量?如何使用Semaphore?
答:Semaphore信号量是一种多线程协调机制,可以控制同时访问某个资源的线程数量。可以使用Semaphore类来创建和使用Semaphore信号量。
-
常用的并发工具类有哪些?
Java提供了很多并发工具类,常用的有:
- CountDownLatch:一个同步辅助类,用于等待一组线程执行完毕后再执行主线程。
- CyclicBarrier:另一个同步辅助类,用于等待一组线程互相等待,直到所有线程都到达某个公共屏障点。
- Semaphore:一个计数信号量,用于控制同时访问某个资源的线程数量。
- Exchanger:一个用于线程间数据交换的工具类,可以实现两个线程之间数据交换。
- ConcurrentHashMap:线程安全的HashMap,用于在多线程环境下进行高效的数据访问。
- BlockingQueue:阻塞队列,用于在多线程环境下进行数据交换。
- Lock:JDK提供的新一代锁,与synchronized关键字相比,具有更灵活的线程同步机制和更好的性能。
- Executor和ExecutorService:线程池的实现类,用于管理和调度线程池中的线程。
- Future和FutureTask:Future表示一个异步计算的结果,FutureTask则是对Future的一个实现,可以用于异步执行任务并获取结果。
-
什么是CountDownLatch类?Java中如何使用CountDownLatch类?
答:CountDownLatch类是一个倒计时计数器类,可以用于控制线程的执行顺序。可以使用CountDownLatch类的await()方法等待计数器归零,使用countDown()方法减少计数器的值。
-
什么是CyclicBarrier类?Java中如何使用CyclicBarrier类?
答:CyclicBarrier类是一个循环屏障类,可以用于多个线程等待彼此达到同步点后再执行后续操作。可以使用CyclicBarrier类的await()方法等待所有线程到达同步点,使用reset()方法重置屏障状态。
-
CountDownLatch和CyclicBarrier的区别是什么?
- CountDownLatch:主要用于等待一个或多个线程完成操作,即在一个线程等待若干个其他线程执行完后再执行。CountDownLatch通过一个计数器实现,计数器的初始值由程序设置,每当一个线程完成任务后,计数器的值减1,当计数器值变为0时,等待的线程就会被唤醒执行。CountDownLatch是一次性的,计数器值为0后不能再重置。
- CyclicBarrier:主要用于控制多个线程之间相互等待,直到所有线程都完成任务后再一起继续执行下一步操作。CyclicBarrier也是通过一个计数器实现,计数器的初始值由程序设置,每当一个线程完成任务后,计数器的值减1,当计数器值变为0时,所有等待的线程都会被唤醒执行。CyclicBarrier可以重复使用,计数器值变为0后会自动重置为初始值。
总的来说,CountDownLatch适用于一次性等待,而CyclicBarrier适用于多次等待,可以重复使用。
-
什么是乐观锁和悲观锁?
悲观锁是一种较为保守的锁策略,它认为在访问共享资源时一定会出现竞争,因此在访问共享资源时直接上锁,阻塞其他线程的访问。悲观锁适用于并发竞争比较激烈的场景,如数据库事务的并发控制。常见的悲观锁实现方式包括synchronized关键字和ReentrantLock。
相比之下,乐观锁则是一种更为乐观的锁策略,它认为在访问共享资源时不会出现竞争,因此不会阻塞其他线程的访问。当发现对共享资源的修改被其他线程抢先完成时,乐观锁会进行回滚并重试。乐观锁适用于并发竞争比较轻的场景,如无锁并发算法和CAS操作。常见的乐观锁实现方式包括版本号机制和CAS操作。
-
什么是读写锁?如何使用读写锁?
答:读写锁是一种特殊的锁机制,可以在读取操作时允许多个线程同时访问,但在写入操作时只允许一个线程访问。可以使用ReentrantReadWriteLock类来实现读写锁。
-
什么是锁的重入?如何实现锁的重入?
答:锁的重入是指同一线程可以多次获取同一把锁,即可重入锁。Java中的synchronized关键字就是一种可重入锁,每个锁对象都对应一个计数器,当线程多次获得同一把锁时,计数器会递增,当计数器递减为0时,锁被释放。Java中有多个可重入锁,包括synchronized关键字、ReentrantLock类、ReentrantReadWriteLock类等。
-
什么是CAS操作?Java中有哪些CAS相关的类?
答:CAS(Compare And Swap)操作是指比较并交换(Compare and Swap),是一种原子性操作,是一种实现线程安全的机制,可以在多线程环境下实现非阻塞的同步。Java中可以使用Atomic类和Unsafe类等实现CAS操作。
-
CAS会造成什么问题?
CAS(Compare and Swap)是一种无锁算法,它通过比较内存中的值与期望值是否相等来判断是否更新内存中的值,从而实现对内存中的变量进行原子操作。与传统的锁机制相比,CAS具有并发性高、性能好、非阻塞等优点。
但是,CAS也会存在一些问题,主要包括以下两点:
- ABA问题:CAS只能保证当内存中的值与期望值相等时才进行更新,而在某些情况下,内存中的值可能发生了多次变化,回到了与之前相同的值,这就是ABA问题。例如,一个线程读取了某个变量的值为A,然后该变量的值被改为B,接着又被改为A,此时另一个线程也读取了该变量的值为A,这时使用CAS进行更新时,会认为变量的值没有发生改变,而实际上变量已经发生了变化。
- 自旋时间过长:在使用CAS时,如果由于竞争太激烈或者CAS失败的次数过多导致自旋时间过长,会浪费CPU资源,降低系统的整体性能。
针对ABA问题,Java提供了AtomicStampedReference和AtomicMarkableReference类,它们在原子性的基础上增加了版本号或标记位,从而避免了ABA问题的发生。而对于自旋时间过长的问题,可以通过调整自旋次数、引入阈值等方式来解决。
-
什么是AQS?
AQS,全称是AbstractQueuedSynchronizer,是Java并发包中一个非常重要的工具类,用于构建同步器。它提供了一种高效且易于使用的方式来构建线程安全的同步器。AQS使用一个双向队列来维护等待队列,可以通过继承AQS来实现同步器。
AQS提供了两种同步模式:独占模式和共享模式。独占模式指的是只允许一个线程访问共享资源,典型的应用是ReentrantLock,而共享模式指的是允许多个线程同时访问共享资源,典型的应用是CountDownLatch、Semaphore等。
在AQS的实现中,主要使用了CAS(Compare and Swap)操作来实现原子性操作,这样就避免了使用synchronized等同步关键字所带来的性能问题。AQS也提供了一些重要的方法,比如acquire()、release()、tryAcquire()、tryRelease()等,通过这些方法可以实现同步器的各种功能。
-
什么是ReadWriteLock?什么是ReentrantReadWriteLock?
ReadWriteLock
是Java中用于支持读写分离锁的接口,它定义了获取读锁和写锁的方法,从而使多个线程可以同时读取某个共享资源,而对该资源进行写操作时,只能有一个线程进行。相比于简单的互斥锁,读写锁的并发性能更好。ReentrantReadWriteLock
是ReadWriteLock
接口的一个实现类。与普通的ReadWriteLock
不同的是,ReentrantReadWriteLock
允许对读锁和写锁进行重入,即同一个线程可以多次获取同一个读锁或写锁,从而避免了由于线程自身获取锁而导致的死锁情况。ReentrantReadWriteLock
中的读写锁都是独立的,读锁之间不互斥,读锁和写锁之间互斥,写锁之间互斥。在读多写少的场景中,使用ReentrantReadWriteLock
可以提高程序的并发性能。但是需要注意的是,使用ReentrantReadWriteLock
可能会导致写饥饿的问题,即写锁可能会因为读锁的频繁获取而长时间无法获得锁。因此,在选择锁的时候需要根据实际情况进行选择。
关注公众号获取简历模板、面试题库、大厂面试题等资源!
更多内容,请关注我的公众号:JAVA大饭桶
相关文章:
应届生Java面试50题线程篇(含解析)
什么是线程? 答:线程是操作系统能够进行运算调度的最小单位,是程序执行流的最小单元。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。 创建线程的方式有哪些?各自的优缺点是什么? 继承 Thread 类&…...
【数据库】第七章 数据库设计
第七章数据库设计 数据库设计概述 数据库设计的基本步骤 需求分析概念结构设计逻辑结构设计物理结构设计数据库实施数据库运行和维护 需求分析 收集需求,理解需求 收集各个角色的需求 概念数据库设计 建立概念模型 ,E-R图/IDEF1x图 消除冲突&…...
Burp Suite 常用模块简介
Burp Suite 常用模块分为 目标站点(target)模块 代理(proxy)模块 攻击(Intruder)模块 重放(Repeater) 模块 Target模块是对站点资源的收集,与站点各资源包发出和相应包的记录 Proxy模块是核心模块,可以拦截数据包发送往浏览器,进行修改后再…...
QML Item和Rectangle详解
1.Item和Rectangle Item类型是Qt Quick中所有可视项的基本类型。 Qt Quick中的所有可视项都继承Item。尽管Item对象没有视觉外观,但它定义了视觉项中常见的所有属性,例如x和y位置、宽度和高度、锚定和键处理支持。 Rectangle继承自Item,多…...
常见前端基础面试题(HTML,CSS,JS)(六)
GET 和 POST 的区别 从 http 协议的角度来说,GET 和 POST 它们都只是请求行中的第一个单词,除了语义不同,其实没有本质的区别。 之所以在实际开发中会产生各种区别,主要是因为浏览器的默认行为造成的。 受浏览器的影响…...
深度学习 李沐报错
3.6. softmax回归的从零开始实现 — 动手学深度学习 2.0.0 documentation softmax从0开始实现 函数执行需要加main指定 改成这样 if __name__"__main__":print(evaluate_accuracy(net, test_iter)) 不然会这样出错 RuntimeError: An attempt has been m…...
【JAVA程序设计】(C00104)基于Springboot的家庭理财管理系统——有文档
基于Springboot的家庭理财管理系统项目简介项目获取开发环境项目技术运行截图运行视频项目简介 基于Springboot开发的家庭理财管理系统设计与实现共分为三个角色:系统管理员、家庭管理员、家庭用户 管理员角色包含以下功能: 用户管理、修改密码、角色管…...
【第五章 AOP概述,底层原理,AOP术语,切入点表达式,AOP操作(基于注解方式,基于xml配置文件)】
第五章 AOP概述,底层原理,AOP术语,切入点表达式,AOP操作(基于注解方式,基于xml配置文件) 1.AOP概述: (1)什么是AOP: ①面向切面编程(…...
面试官: 你知道 JWT、JWE、JWS 、JWK嘛?
想起了 之前做过的 很多 登录授权 的项目 它相比原先的session、cookie来说,更快更安全,跨域也不再是问题,更关键的是更加优雅 ,所以今天总结了一篇文章来介绍他 JWT 指JSON Web Token,如果在项目中通过 jjwt 来支持 J…...
基于企业微信应用消息的每日早安推送
基于企业微信应用消息的每日早安推送 第一步:注册企业微信 企业微信注册地址:https://work.weixin.qq.com/wework_admin/register_wx 按照正常流程填写信息即可,个人也可以注册企业微信,不需要公司 注册完成后,登录…...
【数字IC基础】黑盒验证、白盒验证、 灰盒验证
文章目录 一、黑盒验证二、白盒验证三、灰盒验证一、黑盒验证 1、黑盒验证:大多数基于仿真的验证环境都是黑盒验证;2、不需要知道设计的内部结构和特性,只需要在输入端口打激励,观察输出即可;3、验证工程师学习设计的规格,然后编写验证环境中的 drivers, monitors, check…...
管理的本质是达成目标
“没有目标,其实就没有管理学存在的意义。要有效地使用管理学的智慧,首先要建立清晰的目标。” - 《宁向东的管理学课》 起源 最近开始刷很久之前就在得到上买了的已经起灰了的课程,看到这句话觉得很有道理。 思考 这里面有一个很重要的词…...
【数字IC基础】IC(Integrated Circuit,集成电路)常用缩写
文章目录 1、集成电路:2、数字IC设计相关步骤:3、数字设计相关概念:4、验证相关:5、语言类:6、IC设计相关工具:7、存储器相关:8、总线协议类:9、文件格式类:10、标准和规范:11、其它:1、集成电路: 缩写全称中文翻译LSILarge-scale intergrated circuit大规模集成电…...
JavaScript 高级1 :面向对象
JavaScript 高级1 :面向对象 Date: January 16, 2023 Text: 面向对象、ES6中类和对象、类的继承、面向对象案例 目标: 能够说出什么是面向对象 能够说出类和对象的关系 能够使用 class 创建自定义类型 能够说出什么是继承 面向对象编程介绍 面向过…...
C语言结构体对齐
1. 结构体对齐 要点 变量只能存储在他的长度的整数倍地址上结构体整体对齐跟他的最长的字段整数倍对齐 栗子1 struct Example1 {char a; //1个字节int c; //4个字节short b; //2个字节 };std::cout << sizeof(Example1 ) << std::endl; // 12 std::cout &…...
Bootstrap系列之导航
Bootstrap导航 可以在 ul 元素上添加 .nav类,在每个 li 选项上添加 .nav-item 类,在每个链接上添加 .nav-link 类: 基本的导航 <div class"container mt-3"><h2>导航</h2><p>简单的水平导航:</p><ul class&…...
Java EE|TCP/IP协议栈之应用层协议DNS详解
文章目录一、对DNS的感性认识简介特点一些常见疑问二、DNSDNS域名结构域名的分级三、域名服务器四、域名解析过程参考一、对DNS的感性认识 简介 DNS,即Domain Name System,是域名系统的简称。它是Internet上解决网上机器命名的一种系统。 TCP/IP中的IP地址是由四…...
【MyBatis】作用域生命周期(四)
🚗MyBatis学习第四站~ 🚩起始站:MyBatis概述&环境搭建(一) 🚩本文已收录至专栏:数据库学习之旅 👍希望您能有所收获 一.引入 为了使用方便,我们经常能看到各种教程都将MyBatis抽离为工具类…...
腾讯一面—Android 系统启动流程详解
正文AMS 是 Android 中最核心的服务之一,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,它本身也是一个 Binder 的实现类,应用进程能通过 Binder 机制调用…...
【Python知识点桂电版】02组合数据类型
一、序列序列简介序列是指一种包含多项数据的数据结构,分为不可变序列和可变序列。可变序列可修改序列内的元素如列表,二不可变序列一旦建立就不能修改其中的元素,字符串和元组属于不可变序列。列表和元组的创建列表:列表名 [元素…...
LeetCode100_100. 相同的树
LeetCode100_100. 相同的树 一、描述 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 示例 1: 输入:p [1,2,3], q […...
javaEE 初阶 — 网络层中 IP 协议 的报文结构
文章目录IP 协议报文4位版本号4位首部长度8位服务类型16位总长度(字节数)8位生存时间(TTL)与 8位协议16位首部校验和32位源 IP 地址与32位目标 IP 地址动态分配的 IP 地址NAT 网络地址转换IPv6IP 协议报文 4位版本号 这里的 IP 协…...
iOS swift UICollectionView
文章目录1.纯代码自定义UICollectionViewCell2.禁止滑动(弹簧效果)3.UICollectionView的长按拖动2.在一个控制器中放两个UICollectionView或者UITableView,代理方法要怎么写1.纯代码自定义UICollectionViewCell import UIKitclass NewDeviceBottomColle…...
计算机三级数据库 填空题汇总
计算机三级 数据库 IDEF0需求建模方法由箭头和(活动/方框/矩形)两种元素构成。、从安全性角度考虑,防火墙技术是用来保证数据库应用系统的(网络)环境安全的。在UML的状态机图中,状态之间的转移是由&#x…...
【Java学习】初识Java
JavaSEJava初识1. Java简介2.Java环境的安装与配置3. 开发第一个Java程序Java初识 学前疑问:(带着疑问去学习,在学习中自行探索答案) Java是什么?能做什么?发展前景如何?需要学习哪些内容&…...
LabVIEW网络服务安全
LabVIEW网络服务安全如何保护Web服务?当许多人考虑安全性时,他们会考虑加密、用户ID和密码。用户ID和密码用于授权(告诉目标谁在发出请求)。加密保护客户端和服务器之间的通信流量,以便未经授权的个人无法拦截和读取发…...
基于MaixBit(K210芯片)的图像识别猜拳手势博弈装置
本文介绍了一种基于嵌入式平台开发的图像识别部署装置,其主要功能包括实现机器与人的“猜拳博弈”,其组成分为三个部分:手势检测数据集图像识别模型训练模型格式部署maixbit开发板部署手势检测数据集:本项目的数据集包括三种标签&…...
leetcode 41~50 学习经历
leetcode 41~50 学习经历41. 缺失的第一个正数42. 接雨水43. 字符串相乘44. 通配符匹配45. 跳跃游戏 II46. 全排列47. 全排列 II48. 旋转图像49. 字母异位词分组50. Pow(x, n)小结41. 缺失的第一个正数 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的…...
SQL注入原理及漏洞利用(入门级)
文章目录一、什么是SQL注入漏洞?二、 SQL查询语句三、SQL注入分类数字型(整型)注入字符型注入搜索型注入四、SQL注入漏洞形成原因一、什么是SQL注入漏洞? 攻击者利用Web应用程序对用户输入验证上的疏忽,在输入的数据中…...
2023/2/26 Vue学习笔记 配置代理解决跨域[CORS ]的问题
利用vue的脚手架巧妙的解决ajax跨域的问题 1 我们首先利用springboot服务搭建 注意这里引出了跨域[CORS ]的问题: Access to XMLHttpRequest at http://localhost:5000/getUserInfo from origin http://localhost:8080 has been blocked by CORS policy: No Access-Control-A…...
网站建设微信公众号小程序制作/今日足球比赛分析推荐
点击上方“iOS开发”,选择“置顶公众号”关键时刻,第一时间送达!作者:mirrorzyb链接:https://www.jianshu.com/p/5d836e89d9d1iOS开发整理发布,转载请联系作者获得授权Fastlane是一套使用Ruby写的自动化工具…...
济南地铁建设/googleseo服务公司
[sizex-large][colorred]Java集合框架之fastutil [/color][/size][url]http://rensanning.iteye.com/blog/1548162[/url] fastutil扩展了 Java集合框架,通过提供特定类型的map、set、list和queue,以及小内存占用、快速访问和插入;也提供大&am…...
微网站建设费用/社交网络推广方法
spring_boot打jar包及打包错误的解决方法参考文章: (1)spring_boot打jar包及打包错误的解决方法 (2)https://www.cnblogs.com/penglei-it/p/springboot_package.html 备忘一下。...
高端网站设计收费/谷歌优化师
数字化时代客户体验管理与卓越厅堂服务课程背景: 数字化浪潮下,很多网点存在以下问题:不清楚如何提升网点数字化客户体验?不清楚网点数字化客户体验应用案例?不积善成德如何打造网点卓越厅堂服务? 课…...
猪八戒做网站要多少钱/百度问答平台入口
这篇文章转贴的原因是我老婆在操作ORACLE的 CLOB数据类型进行关联比较提示了 00932的错误, 比较LOB大对象应当使用dbms_lob.compare函数(下面文章有提到具体的使用).主要是用来存储大量数据的数据库字段,最大可以存储4G字节的非结构化数据。主要介绍字符类型和二进制…...
怎么用织梦模板做网站/如何网络推广新产品
2019独角兽企业重金招聘Python工程师标准>>> wampserver开启php_ldap扩展问题记录 在win7(64位)下使用wampserver,开启php_ldap扩展问题,除了要在php.ini中配置外,还要把php_ldap必须的 libsasl.dll依赖放…...