Java并发编程2

2023-06-23  本文已影响0人  我要离开浪浪山

1、启动

启动线程的方式只有:
1、X extends Thread;,然后 X.start
2、X implements Runnable;然后交给 Thread 运行

2、线程的状态

Java 中线程的状态分为 6 种:

状态之间的变迁如下图所示


image.png

3、死锁

是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信
而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统
处于死锁状态或系统产生了死锁。

4、java中死锁的发生必须具备的四个条件

在Java中,死锁的发生必须满足以下四个条件:

只有同时满足以上四个条件,才能导致死锁的发生。在编写多线程程序时,需要注意避免死锁的发生,比如通过避免循环等待、避免占用过多的资源等方式来减少死锁的可能性。

只要打破四个必要条件之一就能有效预防死锁的发生。

5、ABA 问题。

因为 CAS 需要在操作值的时候,检查值有没有发生变化,如果没有发生变化
则更新,但是如果一个值原来是 A,变成了 B,又变成了 A,那么使用 CAS 进行
检查时会发现它的值没有发生变化,但是实际上却变化了。

ABA 问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量
更新的时候把版本号加 1,那么 A→B→A 就会变成 1A→2B→3A。

6、循环时间长开销大。

自旋 CAS 如果长时间不成功,会给 CPU 带来非常大的执行开销。

7、Jdk 中相关原子操作类的使用

image.png

8、常用阻塞队列

·ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
·LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
·PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
·DelayQueue:一个使用优先级队列实现的无界阻塞队列。
·SynchronousQueue:一个不存储元素的阻塞队列。
·LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
·LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
以上的阻塞队列都实现了 BlockingQueue 接口,也都是线程安全的。

9、为什么要用线程池?

10、sychronied修饰普通方法和静态方法的区别?什么是可见性? 锁分哪几类?

synchronized修饰普通方法和静态方法的区别:

可见性:Java中的可见性是指当一个线程修改了共享变量的值后,其他线程能够立即看到修改后的值。在多线程环境下,由于线程之间的执行时机是不确定的,可能会出现某个线程修改了共享变量的值,但是其他线程还没有看到修改后的值的情况,这种情况被称为可见性问题。

锁分为以下几类:

11、CAS无锁编程的原理。

CAS(Compare And Swap)是一种无锁(Lock-Free)的同步算法,它的原理是:当多个线程尝试同时更新同一个共享变量时,只有其中一个线程能够成功地更新该变量的值,而其他线程则不能更新值,会返回失败。CAS操作包含三个操作数:内存地址V、旧的预期值A、新的值B。当且仅当V的值等于A时,才会将V的值更新为B,否则什么都不做。整个比较并交换的操作是一个原子操作。

CAS操作的流程如下:

由于CAS操作不需要加锁,所以它可以避免锁带来的性能问题,从而提高程序的并发性能。但是,CAS操作也存在ABA问题,即当一个值从A变成B再变成A时,CAS操作会认为它没有发生变化,这个问题可以通过加上版本号来解决。

总的来说,CAS无锁编程的原理就是通过原子操作比较并交换,来保证多个线程同时更新共享变量时的正确性和一致性。

12、ReentrantLock的实现原理。

ReentrantLock是一个可重入的互斥锁,它的实现原理主要是基于AQS(AbstractQueuedSynchronizer)的实现。AQS是Java中的一个同步框架,它提供了一种通用的、灵活的、可扩展的同步机制,可以用于实现各种同步器,如锁、信号量、倒计时门栓等。

ReentrantLock的实现原理如下:

ReentrantLock的实现原理中,AQS中的同步状态代表着锁的状态,它可以是0、1或者更大的数。当同步状态为0时,表示该锁没有被任何线程持有;当同步状态为1时,表示该锁已经被一个线程持有;当同步状态大于1时,表示该锁已经被多个线程持有,即可重入锁的实现。

总的来说,ReentrantLock的实现原理是基于AQS的实现,通过维护一个等待队列和一个同步状态来实现锁的控制,从而提供了可重入、公平和非公平锁等多种功能。

13、AQS原理

AQS(AbstractQueuedSynchronizer)是Java中的一个同步框架,它提供了一种通用的、灵活的、可扩展的同步机制,可以用于实现各种同步器,如锁、信号量、倒计时门栓等。
AQS的实现原理主要是基于一个FIFO的双向队列和一个同步状态变量。同步状态变量可以是任何类型的原子变量,如int、long、自定义的对象等。
AQS的核心思想是,将所有需要同步的线程封装成一个个node节点,每个线程在尝试获取同步状态时,都会在队列中创建一个node节点,然后将该节点加入到队列的尾部,成为等待队列中的一员。当同步状态可用时,AQS会从队列的头部开始遍历,寻找下一个可以获得同步状态的节点,让它去获得同步状态,从而实现线程的同步。

AQS的实现原理可以归纳为以下几个步骤:

AQS的实现原理中,FIFO的双向队列用于维护等待线程的顺序,同步状态变量用于表示锁的状态,而node节点则用于表示等待队列中的线程。

总的来说,AQS的实现原理是基于一个FIFO的双向队列和一个同步状态变量来实现的,它提供了一种通用的、灵活的、可扩展的同步机制,可以用于实现各种同步器。

14、Synchronized的原理以及与ReentrantLock的区别。

Synchronized是Java中的一种内置锁,它可以用于实现线程之间的同步。Synchronized的实现原理是基于Java中的监视器(Monitor)机制实现的。每个Java对象都有一个关联的监视器对象,当一个线程获取了对象的内置锁,就意味着该线程获取了对象关联的监视器对象的锁。当一个线程进入某个Synchronized代码块时,它会自动获取对象关联的监视器对象的锁,当线程执行完Synchronized代码块时,它会释放对象关联的监视器对象的锁,从而实现线程间的同步。

Synchronized的实现原理可以归纳为以下几个步骤:

ReentrantLock是Java中的另一种锁,它与Synchronized相比,提供了更多的功能,如可重入锁、公平锁和非公平锁等。ReentrantLock的实现原理是基于AQS(AbstractQueuedSynchronizer)实现的,它通过维护一个等待队列和一个同步状态来实现锁的控制,从而提供了可重入、公平和非公平锁等多种功能。

Synchronized与ReentrantLock的区别如下:

总的来说,Synchronized和ReentrantLock都是Java中的锁,它们的实现原理和作用都有所不同,开发者需要根据具体的需求选择合适的锁。在Java 5之后,ReentrantLock已经成为Java中的主流锁,因为它提供了更多的功能和更好的性能。

15、Synchronized做了哪些优化

Synchronized是Java中最基本的线程同步机制,它能够很好地保证线程的安全性,但是它的性能不一定很高。为了提高Synchronized的性能,Java语言设计者对Synchronized进行了一些优化,主要包括以下几个方面:

这些优化措施可以让Synchronized的性能得到提升,但是它们只是一些辅助性的措施,最根本的还是需要开发者自己写出高效的代码。

16、volatile 能否保证线程安全?在DCL上的作用是什么?

volatile能够保证线程可见性和禁止指令重排序,但是它并不能保证线程安全。线程安全需要通过锁机制来实现。

volatile关键字主要是为了保证线程之间的可见性。在多线程环境下,每个线程都有自己的工作内存和缓存,当一个线程修改了某个共享变量的值时,其他线程不一定能够立即看到这个修改。这是因为在多线程环境下,为了提高效率,每个线程都会从主存中读取共享变量的值到自己的本地缓存中,当它修改变量值后,也是将修改后的值写入本地缓存中。因此,当一个线程修改了变量值后,其他线程不一定能够立即看到修改。

volatile关键字能够解决这个问题,它可以让共享变量的值在多线程之间保持一致,即当一个线程修改了共享变量的值后,其他线程可以立即看到这个修改。这是因为volatile关键字会强制将修改后的值立即写入主存中,并且禁止指令重排序,从而保证其他线程可以立即看到修改。

在DCL(Double Checked Locking)中,volatile关键字的作用是保证DCL的正确性。DCL是一种延迟初始化的方式,它可以在多线程环境下保证只有一个实例被创建。但是,在不加volatile的情况下,由于指令重排序的存在,可能会导致另一个线程在第一次检查时获取到了未被完全初始化的实例,从而导致DCL的失败。加上volatile后,可以禁止指令重排序,从而保证DCL的正确性。

17、volatile和synchronize有什么区别?

volatile和synchronized都是Java中用于多线程同步的关键字,但是它们有着不同的作用和使用场景:

综上所述,volatile和synchronized虽然都是Java中用于多线程同步的关键字,但是它们的作用、锁的范围、性能和使用场景有着不同的特点,需要根据实际情况进行选择。

18、什么是守护线程?你是如何退出一个线程的?

1、守护线程:
守护线程在Java中,守护线程(Daemon Thread)是一种特殊的线程,它的作用是为其他线程提供服务。守护线程是一种支持性线程,当所有非守护线程结束时,守护线程也会自动退出。守护线程通常用于在后台执行一些周期性的任务,比如垃圾回收等。

Java中的守护线程可以通过以下两种方式创建:

2、退出一个线程
线程的退出可以通过以下两种方式实现:

需要注意的是,如果线程中有一些资源(如文件、数据库连接、网络连接等)需要释放,那么在退出线程之前,需要将这些资源进行释放,避免资源泄露和其他问题。可以通过在finally块中进行资源释放来实现。

19、sleep 、wait、yield 的区别,wait 的线程如何唤醒它?

1、sleep、wait、yield的区别

sleep、wait、yield都是Java中用于线程控制的关键字,它们的作用和使用场景有所不同:

2、wait的线程如何唤醒它

当一个线程调用wait方法时,它进入等待状态,并释放对象的锁。其他线程可以获得该对象的锁,并调用notify或notifyAll方法来唤醒处于等待状态的线程。notify方法将会随机唤醒一个处于等待状态的线程,而notifyAll方法会唤醒所有处于等待状态的线程。

需要注意的是,调用wait方法和notify/notifyAll方法的线程必须持有该对象的锁,否则会抛出IllegalMonitorStateException异常。此外,等待线程被唤醒后,它必须重新获得对象的锁才能继续执行。

20、sleep是可中断的么?

sleep方法是可中断的,当另一个线程调用了sleep方法所在线程的interrupt方法时,sleep方法会抛出InterruptedException异常并立即返回,同时清除该线程的中断状态。此时,该线程可以根据自己的需要进行处理,如退出或继续执行。如果该线程在调用sleep方法之前已经被中断过一次,那么在调用sleep方法时会立即抛出InterruptedException异常。

因此,在使用sleep方法时,需要在catch块中处理InterruptedException异常,以确保程序正确性。

21、线程生命周期

Java中的线程生命周期可以分为5个阶段:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Terminated)。

总之,线程生命周期的不同阶段表示了线程的不同状态和执行情况,了解这些阶段可以帮助我们更好地理解和掌握Java中的线程编程。

21、ThreadLocal是什么?

ThreadLocal是Java中的一个线程本地变量类,它提供了一种线程私有的变量机制。每个ThreadLocal对象都可以为一个线程维护一个值,这个值可以在这个线程的任何地方被获取和修改,但是其他线程并不能访问到这个值。换句话说,ThreadLocal为每个线程都创建了一个独立的变量副本,每个线程之间互不干扰,互相隔离。ThreadLocal通常被用于在多线程环境下实现线程安全的变量访问,尤其是在变量的值需要在多个方法中共享、但又不希望使用synchronized进行同步的情况下。在这种情况下,我们可以将变量声明为ThreadLocal类型,使得每个线程都可以独立地访问这个变量,从而避免了线程安全问题。

ThreadLocal的常用方法包括:

需要注意的是,ThreadLocal虽然能够提供线程本地变量的机制,但是过多地使用ThreadLocal也会带来一些问题,比如可能会导致内存泄漏或引发不可预期的问题等。因此,在使用ThreadLocal时,需要注意变量的作用域和生命周期,避免滥用。

22、线程池基本原理。

线程池是一种线程管理机制,它通过预先创建一定数量的线程,并将它们保存在一个线程池中,以便随时使用,从而避免了线程创建和销毁的开销,提高了线程的重用性和执行效率。

线程池的基本原理如下:

需要注意的是,线程池中的线程是复用的,当线程执行完一个任务后,它还可以被用来执行其他任务,而不是被销毁。这种复用机制可以避免线程创建和销毁的开销,提高线程的执行效率。同时,线程池还提供了一些管理机制,比如可以设置线程池中的线程数量、任务队列的大小等,以及对超时任务的处理等,这些都可以进一步提升线程池的性能和可靠性。

23、有三个线程T1,T2,T3,怎么确保它们按顺序执行?

可以使用以下方法来确保三个线程按照指定顺序执行:

需要注意的是,以上三种方法都需要保证对共享变量的访问是同步的,以避免出现竞态条件和数据不一致的问题。同时,需要保证三个线程之间的通信是可靠的,以确保每个线程都能按照指定的顺序执行。

上一篇 下一篇

猜你喜欢

热点阅读