当前位置: 首页 > news >正文

Java面试宝典-并发编程学习02

目录

21、并行与并发有什么区别?

22、多线程中的上下文切换指的是什么?

23、Java 中用到的线程调度算法是什么?

24、Java中线程调度器和时间分片指的是什么?

25、什么是原子操作?Java中有哪些原子类?

26、wait与notify的区别?

27、为什么 wait()、notify()、notifyAll()必须在同步方法或者同步块中被调用?

28、Thread 类中的 yield 方法有什么作用?

29、yield、sleep和 wait 有什么区别?

30、Java 如何实现多线程之间的通讯和协作?

31、JVM 对 Java 的原生锁做了哪些优化?

32、守护线程是什么?它是如何实现的?

33、为什么代码会重排序?

34、java如何实现线程的同步

35、说说多线程的三大特性

原子性

可见性

有序性

36、java 有序性问题?

37、Java中提供了哪些类解决多线程特性问题?

38、说说你对内存区域的理解?

39、说说你对Java内存模型的理解?

1. 主内存与工作内存

2. 变量访问规则

3. 原子性、可见性和有序性

40、说说你对Happens-Before原则的理解?

Happens-Before原则的基本内容

Happens-Before原则的意义


21、并行与并发有什么区别?

并发和并行的区别为:意思不同、侧重不同、处理不同。

一、意思不同

1、并发:并发是指两个或多个事件在同一时间间隔发生,把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。

2、并行:并行是指两个或者多个事件在同一时刻发生,把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。

二、侧重不同

1、并发:并发侧重于在同一实体上。

2、并行:并行侧重于在不同实体上。

三、处理不同

1、并发:并发在一台处理器上“同时”处理多个任务。

2、并行:并行在多台处理器上同时处理多个任务

22、多线程中的上下文切换指的是什么?

多线程中的上下文切换是指在多线程环境中,当一个线程执行完毕或被暂停时,操作系统需要将当前线程的上下文保存起来,并切换到另一个线程的执行。‌ 上下文切换涉及保存当前线程的寄存器状态、程序计数器值等信息,并将另一个线程的上下文恢复到处理器中,以便继续执行‌。

(1)上下文切换通常发生在以下两种情况:

① 时间片用尽,在分时操作系统中,CPU为每个线程分配一定的时间片,当线程的时间片耗尽时,操作系统会将CPU的控制权交给下一个线程。

② 线程阻塞或等待,当线程需要等待某个事件(如I/O操作完成)或因互斥锁等原因进入阻塞状态时,操作系统会选择另一个可运行的线程

来继续执行。

(2)上下文切换包含两个过程:

① 保存状态,操作系统会将当前线程的执行状态(如寄存器值、程序计数器等)保存到内存中,这个过程称为“切出”。

② 加载状态,随后,操作系统会从内存中加载另一个线程的执行状态,使其继续在CPU上运行,这个过程称为“切入”。

上下文切换是操作系统多任务管理的一个重要组成部分,它允许多个线程在单个CPU上交替运行,从而实现并发执行。然而,频繁的上下文切换会增加系统的开销,因为每次切换都需要保存和加载线程状态,这会消耗CPU时间和内存资源。因此,在设计多线程程序时,应当尽量减少不必要的上下文切换,以提高系统的整体效率。

23Java 中用到的线程调度算法是什么?

Java 中用到的线程调度算法主要是时间片轮转和优先级抢占,具体实现依赖于各种 JVM 和操作系统的情况。

1、优先级抢占

在这种模式下,更高优先级的线程会优先执行。与时间片轮转不同,线程不需要轮流运行,而是在满足条件后以无限期等待的方式运行。当更高优先级的任务出现时,调度器会中断当前线程并执行较高优先级的任务,这种方式也称为"抢占式调度"。

在 Java 中,线程的优先级通常是由 Thread 类提供的 setPriority() 方法或者相应构造函数来设置,优先级范围为 1-10 (默认为 5)。在 JVM 中,越高的优先级任务具有更多的执行机会,但并不能保证所有任务都获得机会。实际上,在某些情况下低优先级任务可能会一直等待而无法执行,而这种情况称为"饥饿问题"。

2、时间片轮转

它通过将处理器时间分成固定周期,并将每个任务分配固定的时间片进行执行,来确保公平性和响应性。

在 Java 中,时间片轮转算法通常是由 JVM 调度器来执行的,其中线程的执行被分为几个连续的时间片,JVM 会根据一定的规则决定当前线程活动时长是否已超过最大时间片,如果该时间已超过,则强制暂停当前线程的执行,并将 CPU 时间片分配给下一个线程。因此,这种算法可以避免线程的永久阻塞并提高系统的容错性。

3、其他算法

除了时间片轮转和优先级抢占外,Java 中还可以使用许多其他类型的调度算法,例如多级反馈队列调度、最短作业优先等,其中多级反馈队列调度也是比较流行且常用的。在该算法中,不同的任务被组织成一个任务序列,并分配到多个不同的容量栏以内。当任务进入队列后,它将被放置在第一列,然后逐渐向前移动,如果该任务需要更多时间才能完成,则移向含有更大时间片的队列。

24Java中线程调度器和时间分片指的是什么?

线程调度器是操作系统内核的一部分,它的主要职责是管理和调度多个线程对CPU资源的使用。在多线程环境下,由于CPU资源有限,需要有一个机制来决定哪个线程将获得CPU的使用权。线程调度器根据不同的算法和策略,如先来先服务(FIFO)、最短作业优先(SJF)、最高优先级优先以及轮转(Round Robin)等,决定线程的执行顺序。

时间分片是一种确保多个线程能够公平共享CPU时间的技术。在这种机制下,CPU的时间被划分成许多小片段,每个片段称为一个时间片。

然后,这些时间片按照某种策略分配给处于可运行状态(Runnable)的线程。时间分片的大小和分配策略可以基于线程的优先级或者等待时间等因素来确定。

线程调度器通过时间分片技术,允许多个线程看似同时地使用单个CPU,从而实现了任务的并发执行。

25、什么是原子操作?Java中有哪些原子类?

‌原子操作是指一个或一系列操作,这些操作在执行过程中不会被其他线程打断,要么全部执行成功,要么全部不执行。‌ 这种特性使得原子操作在并发控制中非常重要,特别是在多线程环境下。原子操作可以是一个步骤,也可以是多个操作步骤,但其顺序不可以被打乱,也不可以被切割而只执行其中的一部分‌。

Java中,原子类位于java.util.concurrent.atomic包中,主要包括以下几种:

(1)基本数据类型的原子类

AtomicInteger:提供原子更新的整数值。

AtomicBoolean:提供原子更新的布尔值。

AtomicLong:提供原子更新的长整数值。

(2)引用类型的原子类

AtomicReference:提供对引用类型的原子更新。

AtomicStampedReference:提供带有版本号的引用类型的原子更新。

AtomicMarkableReference:提供可标记的引用类型的原子更新。

(3)数组类型的原子类

AtomicIntegerArray:提供对整数数组的原子更新。

AtomicLongArray:提供对长整数数组的原子更新。

AtomicReferenceArray:提供对对象数组的原子更新。

26waitnotify的区别?

多个线程在争夺同一个资源时,为了让这些线程协同工作、提高CPU利用率,可以让线程之间进行沟通,具体可以通过wait()和notify()实

现。

1. wait():使当前线程处于等待状态,即阻塞,直到其它线程调用此对象的notify()方法;

2. notify():唤醒在此对象监视器上等待的单个线程,如果有多个线程同时在监视器上等待,则随机唤醒一个;

3. notifyAll():唤醒在此对象监视器上等待的所有线程;

使用时需要注意几点:

1. 三个方法都是Object()类中定义的native方法,而不是thread类提供的,这是因为Java提供的类是对象级的,而不是线程级的;

2. 这三个方法都必须在synchronized修饰的方法或代码块中使用,否则会抛出异常;

3. 使用wait()时,为了避免并发带来的问题,通常建议将wait()方法写在循环的内部。

27、为什么 wait()notify()notifyAll()必须在同步方法或者同步块中被调用?

同步方法或同步块确保了在任一时刻只有一个线程可以执行这些代码区域,这样可以避免多个线程同时访问共享资源时产生竞争。

wait()方法会使当前线程进入等待状态,并释放对象的锁,而notify()和notifyAll()方法用于唤醒在该对象上等待的线程。

这些方法的设计是为了在多线程环境中协调线程的执行顺序和资源共享,如果没有同步机制,无法保证正确的等待和唤醒行为。

如果在非同步的上下文中调用这些方法,可能会导致所谓的“丢失唤醒”问题,即一个线程可能在没有获得锁的情况下被唤醒,这是非常危险的,因为它可能导致线程在不安全的情况下操作共享数据。

由于wait(), notify()和notifyAll()都是对象的方法,它们需要在同步方法或同步块中被调用,以确保线程之间的互斥和同步。这是因为在调用这些方法之前,调用线程必须已经获得了该对象的锁。

28Thread 类中的 yield 方法有什么作用?

‌Thread 类中的yield 方法的主要作用是让当前线程放弃 CPU 时间片,使得其他具有相同优先级的线程有机会被执行。‌ 这个方法是一个静态方法,意味着可以直接通过 Thread.yield() 调用,而不需要创建 Thread 的实例。它的主要目的是将当前线程的 CPU 使用权让给同优先级或者更高优先级的就绪状态线程‌。

具体来说,当调用 yield() 方法时,当前线程会从运行状态转变为就绪状态,这使得其他具有相同优先级的线程有机会获取 CPU 执行权。然而,yield() 方法仅是一个提示,不能保证其他线程一定会获得执行机会。线程调度器可能会忽略这个提示,因此调用 yield() 的线程有可能在进入到阻塞状态后马上又被执行‌。

29yieldsleep wait 有什么区别?

yield()sleep(),  wait() 都是Java多线程编程中用于控制线程执行的方法,但它们在功能和使用场景上有显著的区别。

  1. 所属类和功能差异
    • wait():属于Object类中的非静态方法,用于线程间的通信,会释放对象锁,必须在同步块中调用12
    • sleep():属于Thread类中的静态方法,用于使当前线程暂停执行一段时间,不释放对象锁12
    • yield():同样属于Thread类中的静态方法,用于临时暂停当前线程的执行,让同等优先级的线程有机会执行,但不保证立即让出CPU‌
  2. 使用场景和效果差异
    • wait():适用于需要等待某个条件成立的场景,调用后会释放对象锁,其他线程可以访问该对象。被notify()notifyAll()方法唤醒后,线程会进入就绪状态,等待CPU调度
    • sleep():用于让当前线程暂停执行一段时间,适用于需要休息一段时间再继续执行的场景。不会释放对象锁,适用于不需要等待特定条件的场合
    • yield():用于让出CPU给同等优先级的线程执行,但不保证立即让出CPU,当前线程可能会再次被调度执行
  3. 释放锁的差异
    • wait():会释放当前线程占有的对象锁,其他线程可以访问该对象
    • sleep():不会释放对象锁,当前线程在休眠期间,其他线程无法访问该对象的同步块
    • yield():不会释放对象锁,只是让出CPU给同等优先级的线程执行

代码示例:

public class ThreadExample {public static void main(String[] args) {final Object lock = new Object();Thread thread1 = new Thread(() -> {synchronized (lock) {System.out.println("Thread 1 is running.");try {Thread.sleep(2000); // 让Thread2有机会运行} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 1 is sleeping.");}});Thread thread2 = new Thread(() -> {synchronized (lock) {try {lock.wait(); // 等待通知} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 2 is running after being notified.");}});thread1.start();thread2.start();}
}

30Java 如何实现多线程之间的通讯和协作?

在Java中,实现多线程之间的通讯和协作可以使用Object类中的wait()、notify()和notifyAll()方法,或者使用java.util.concurrent 包中的Condition接口提供的方法。

以下是使用wait()、notify()方法实现线程间通讯的一个简单例子:

class MyTask {private boolean finished = false;public synchronized void doWork() {while (!finished) {try {wait(); // 线程等待} catch (InterruptedException e) {Thread.currentThread().interrupt();}}System.out.println("任务完成");}public synchronized void finishTask() {finished = true;notifyAll(); // 唤醒等待的线程}
}public class ThreadCommunication {public static void main(String[] args) {MyTask task = new MyTask();Thread worker = new Thread(() -> task.doWork());worker.start();// 做一些工作...// 完成任务task.finishTask();}
}

使用Condition接口实现通讯和协作:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;class ConditionTask {private Lock lock = new ReentrantLock();private Condition finished = lock.newCondition();private boolean finishedWork = false;public void doWork() {lock.lock();try {while (!finishedWork) {finished.await(); // 线程等待}System.out.println("任务完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {lock.unlock();}}public void finishWork() {lock.lock();try {finishedWork = true;finished.signal(); // 唤醒等待的线程} finally {lock.unlock();}}}public class ConditionCommunication {public static void main(String[] args) {ConditionTask task = new ConditionTask();Thread worker = new Thread(() -> task.doWork());worker.start();// 做一些工作...// 完成任务task.finishWork();}}

31JVM Java 的原生锁做了哪些优化?

(1)自旋锁

在线程进行阻塞的时候,先让线程自旋等待一段时间,可能这段时间其它线程已经解锁,这时就无需让线程再进行阻塞操作了。

自旋默认次数是10次。

(2)自适应自旋锁

自旋锁的升级,自旋的次数不再固定,由前一次自旋次数和锁的拥有者的状态决定。

(3)锁消除

在动态编译同步代码块的时候,JIT编译器借助逃逸分析技术来判断锁对象是否只被一个线程访问,而没有其他线程,这时就可以取消锁了。

(4)锁粗化

当JIT编译器发现一系列的操作都对同一个对象反复加锁解锁,甚至加锁操作出现在循环中,此时会将加锁同步的范围粗化到整个操作系列的外部。

锁粒度:不要锁住一些无关的代码。

锁粗化:可以一次性执行完的不要多次加锁执行。

32、守护线程是什么?它是如何实现的?

守护线程Daemon Thread是一种在Java中用于执行后台任务的线程。守护线程的主要用途是为其他线程提供服务,例如垃圾回收、系统监控等。它们不会阻止程序的终止,当所有非守护线程结束运行时,程序和所有守护线程都会随之终止

守护线程的实现方法是在线程启动之前调用setDaemon(true)方法。这个方法必须在调用start()方法之前设置,否则会抛出IllegalThreadStateException异常。设置守护线程后,该线程将继续执行其任务,但当所有非守护线程结束时,守护线程也会随之终止

常见的守护线程包括垃圾回收线程等。这些线程在程序运行时在后台提供通用服务,当所有用户线程结束时,守护线程也会自动结束,程序随之退出

示例代码演示如何设置守护线程:

MyDaemonThread myDaemonThread = new MyDaemonThread();
myDaemonThread.setDaemon(true);
myDaemonThread.start();

在这个示例中,MyDaemonThread类继承自Thread类,并在其run()方法中执行后台任务。通过调用setDaemon(true)将其设置为守护线程,该线程将在后台执行任务,当所有非守护线程结束时自动终止

33、为什么代码会重排序?

在Java中,代码重排序是指编译器和处理器为了优化程序性能,可能会调整程序中语句的执行顺序。这种优化是在不改变程序的单线程语义的前提下进行的。

重排序可能会导致如下问题:

可见性问题:如果一个线程基于重排序后的执行顺序对共享变量的写操作对另一个线程不可见,可能导致内存可见性问题。

原子性问题:某些操作(如i++)在多线程环境下可能不是原子的,重排序可能会破坏这些操作的原子性。

解决这些问题的方法是使用volatile关键字,它可以防止重排序,确保变量的可见性;或者使用synchronized关键字,它不仅确保可见性,还确保了原子性,还可以通过final关键字来避免重排序导致的问题。

示例代码:

class Example {volatile boolean flag;public Example() {flag = false; // 显式初始化,防止重排序}public void start() {new Thread(() -> {while (!flag) {// 循环体}}).start();}public void stop() {flag = true; // 更新变量,导致可见性问题}
}

在这个例子中,flag变量被声明为volatile,这样在多线程环境下,就不会出现因为重排序导致的可见性问题。

34java如何实现线程的同步

Java中,实现线程同步的主要方式有以下几种:

1.同步代码块:使用synchronized关键字来保护代码块,确保同一时刻只有一个线程可以进入该代码块。

public void synchronizedMethod() {synchronized(this) {// 需要同步的代码}
}

2.同步方法:在方法声明上使用synchronized关键字,这样的方法称为同步方法。

public synchronized void synchronizedMethod() {// 需要同步的代码
}

3.同步锁:使用ReentrantLock类来实现更灵活的同步控制。

import java.util.concurrent.locks.ReentrantLock;public class MyClass {private final ReentrantLock lock = new ReentrantLock();public void myMethod() {lock.lock();try {// 需要同步的代码} finally {lock.unlock();}}}

4.使用volatile关键字修饰共享变量,可以确保线程之间的可见性,但不提供原子性。

public class SharedObject {public volatile int sharedCount = 0;public void increment() {sharedCount++; // 这个操作是非原子的,可能需要同步}}

  1. 使用Atomic*类,这些类提供了原子操作的支持,例如AtomicInteger
import java.util.concurrent.atomic.AtomicInteger;public class SharedObject {public AtomicInteger sharedCount = new AtomicInteger(0);public void increment() {sharedCount.incrementAndGet(); // 这是一个原子操作,不需要同步}}

35、说说多线程的三大特性

多线程的三大特性是原子性、可见性和有序性。

原子性

原子性是指一个操作或者一系列操作要么全部执行,要么都不执行,不能被其他线程打断。例如,银行转账操作必须保证原子性,即从一个账户扣款和向另一个账户存款这两个操作要么同时成功,要么同时失败,不能出现部分成功的情况

可见性

可见性是指当一个线程修改了共享变量的值,其他线程能够立即看到这个修改后的值。由于JVM的优化和CPU的缓存机制,一个线程对共享变量的修改可能不会立即对其他线程可见,这就是所谓的可见性问题”‌

有序性

有序性是指程序执行的顺序按照代码的先后顺序执行。然而,为了优化性能,JVMCPU会对指令进行重排,这可能会导致代码的执行顺序与代码中的顺序不同。为了确保有序性,Java提供了volatile关键字和synchronized关键字,它们可以保证指令的执行顺序与代码顺序一致

36java 有序性问题?

Java中,有序性问题通常指的是当多个线程并发访问共享数据时,如何保证线程之间的有序性,避免出现意外的行为,如竞态条件、数据不一致等问题。

Java提供了volatile关键字来保证可见性,但不提供任何原子性保证,它不能用于实现计数器、同步队列等。

另外,Java提供的synchronized关键字和Lock接口可以实现原子性,也就是同一时刻只有一个线程可以执行被锁保护的代码块,从而保证了有序性。

下面是一个使用synchronized关键字来保证线程之间有序性的例子:

public class SynchronizedCounter {private int count = 0;public synchronized void increment() {count++; // 这个操作是线程安全的,因为它被synchronized修饰}public synchronized int getCount() {return count; // 这个操作是线程安全的,因为它被synchronized修饰}
}

在这个例子中,increment方法和getCount方法都被synchronized关键字修饰,这意味着在同一时刻只有一个线程可以进入这两个方法中的任何一个,从而保证了操作的有序性。

37Java中提供了哪些类解决多线程特性问题?

Java中提供了多种类和方法来解决多线程特性问题,包括同步锁、原子操作、并发集合、线程局部存储、读写锁和信号量等。

首先,Java提供了同步锁机制,通过synchronized关键字java.util.concurrent.locks包下的锁类(如ReentrantLock)来保护共享资源,确保一次只有一个线程能够访问受保护的代码块

其次,Java利用原子变量类(如AtomicIntegerAtomicBoolean等),提供无锁的线程安全操作,避免线程安全问题

此外,Java提供了并发集合类(如ConcurrentHashMapCopyOnWriteArrayList等),这些集合类在内部实现了线程安全的数据结构,适用于并发编程

另外,Java还提供了线程局部存储ThreadLocal类),为每个线程提供独立的变量副本,避免线程间的变量冲突

对于读写操作频繁的场景,可以使用读写锁ReadWriteLock),允许多个线程同时读取,但写入时独占访问权

最后,使用信号量Semaphore类)可以控制对有限资源的访问,适用于需要控制访问权限的场景3

38、说说你对内存区域的理解?

JVM在运行时,会将其管理的内存区域划分为方法区、堆、虚拟机栈、本地方法栈和程序计数器5个区域; 方法区和堆是所有下城共享的区域; 虚拟机栈、本地方法栈、程序计数器是各个线程私有的.

39、说说你对Java内存模型的理解?

Java内存模型(Java Memory ModelJMM)是Java虚拟机(JVM)的一部分,它定义了共享变量的可见性、原子性和有序性在多线程环境下的行为。Java内存模型是围绕着在并发编程中可能出现的各种问题而建立的,它确保了在多线程环境下,对共享变量的访问是正确和高效的。

1. 主内存与工作内存

Java内存模型主要分为主内存(Main Memory)和工作内存(Working Memory)两部分:

  • 主内存:是Java虚拟机中所有线程共享的内存区域,用于存储共享变量。
  • 工作内存:是每个线程私有的内存区域,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存中的变量。

2. 变量访问规则

线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者之间的交互关系如下:

  • lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
  • unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
  • read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
  • load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
  • use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
  • assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
  • store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
  • write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

3. 原子性、可见性和有序性

Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这三个特征来建立的:

  • 原子性:保证了指令的不可分割性,即操作一旦开始就不会被线程调度机制中断。
  • 可见性:当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。
  • 有序性:程序执行的顺序按照代码的先后顺序执行。

总的来说,Java内存模型是一个复杂但强大的工具,它帮助Java程序员在多线程环境中编写安全、高效的代码。通过理解和应用Java内存模型,程序员可以更好地掌握并发编程的核心概念,并编写出更健壮、更高效的并发程序。

40、说说你对Happens-Before原则的理解?

Happens-Before原则是Java内存模型中用于描述两个操作之间的可见性和有序性的一种规则。这个原则非常重要,因为它帮助开发者理解在多线程环境下,不同线程之间的操作是如何相互影响和可见的。

Happens-Before原则的基本内容

  1. 程序顺序规则:在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。这保证了程序内指令的基本顺序性。
  2. 锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。这意味着,当一个线程释放了一个锁,那么之后其他线程获取这个锁的操作一定是在释放锁的操作之后发生的。
  3. volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个volatile变量的读操作。这保证了volatile变量的可见性,即当一个线程修改了一个volatile变量,其他线程能够立即看到这个修改。
  4. 传递性:如果操作A先行发生于操作B,而操作B又先行发生于操作C,那么可以得出操作A先行发生于操作C
  5. 线程启动规则Thread对象的start()方法先行发生于此线程的每一个动作。这意味着,当一个线程启动后,它的所有操作都是在start()方法调用之后发生的。
  6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过interrupted()方法检测到是否有中断发生。
  7. 线程终结规则:线程中所有的操作都先行发生于对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
  8. 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。

Happens-Before原则的意义

Happens-Before原则为Java程序员提供了一种判断操作之间是否存在先行发生关系的方法。如果两个操作之间存在先行发生关系,那么第一个操作的执行结果将对第二个操作可见,且第一个操作的执行顺序排在第二个操作之前。

这个原则对于编写正确的并发程序非常重要,因为它帮助程序员理解在多线程环境下,不同线程之间的操作是如何相互影响和可见的。通过遵循Happens-Before原则,程序员可以编写出更安全、更高效的并发程序。

相关文章:

Java面试宝典-并发编程学习02

目录 21、并行与并发有什么区别? 22、多线程中的上下文切换指的是什么? 23、Java 中用到的线程调度算法是什么? 24、Java中线程调度器和时间分片指的是什么? 25、什么是原子操作?Java中有哪些原子类? 26、w…...

【每日一题】洛谷 - 快速排序模板

今天的每日一题来自洛谷,题目要求对给定的 N N N 个正整数进行从小到大的排序,并输出结果。我们将使用经典的**快速排序算法(QuickSort)**来解决这一问题。下面我将从问题分析、代码实现、及快速排序的核心思想进行详细说明。 题…...

Django模型优化

1、创建一个Django项目 可参考之前的带你快速体验Django web应用 我使用的是mysql数据库。按照上述教程完成准备工作。 2、创建一个app并完成注册 demo主要来完成创建用户、修改用户、查询用户、删除用户的操作。 python manage.py startapp test0023、app的目录 新建templ…...

Python实现火柴人的设计与实现

1.引言 火柴人(Stick Figure)是一种极简风格的图形,通常由简单的线段和圆圈组成,却能生动地表达人物的姿态和动作。火柴人不仅广泛应用于动画、漫画和涂鸦中,还可以作为图形学、人工智能等领域的教学和研究工具。本文…...

衡石分析平台系统分析人员手册-应用模版

应用模板​ 应用模板使分析成果能被快速复用,节省应用创作成本,提升应用创作效率。此外应用模板实现了应用在不同环境上快速迁移。 支持应用复制功能 用户可以从现有的分析成果关联到新的分析需求并快速完成修改。 支持应用导出为模板功能 实现多个用户…...

Git和SVN

一. Git和SVN的区别 1.1 Git是分布式的,SVN是集中式的 1.2 Git复杂概念多,SVN简单易上手 Git 的命令实在太多了,日常工作需要掌握 add, commit, status, fetch, push, rebase等,若要熟练掌握,还必须掌握 rebase和 m…...

【C语言教程】【常用类库】(十八)宏与预处理 - <stddef.h> 和 <stdbool.h>

18. 宏与预处理 - <stddef.h> 和 <stdbool.h> C语言的宏和预处理指令在程序编译之前就被执行&#xff0c;用于文件包含、符号定义、条件编译等操作。理解和运用宏和预处理可以提高代码的灵活性和可移植性。 18.1 宏定义与条件编译 18.1.1 #define 与参数化宏 #…...

订单超时过期的实现方案的探讨

在我们的业务开发中&#xff0c;会遇到这样一个场景&#xff0c;用户下了一个单&#xff0c;如果超过20分钟不进行支付&#xff0c;订单就要变成已取消状态。 字段设定 订单中需要设定了三个字段&#xff1a;订单是否取消、是否支付、支付超时时间。 订单是否取消会存在&…...

C++中的CRTP

CRTP&#xff0c;全称为 Curiously Recurring Template Pattern&#xff08;奇异递归模板模式&#xff09;&#xff0c;是一种在C中使用继承和模板技术来实现静态多态和功能复用的惯用法。它使用派生类来模板参数化基类&#xff0c;使得基类能够访问派生类&#xff0c;从而在编…...

go压缩的使用

基础&#xff1a;使用go创建一个zip func base(path string) {// 创建 zip 文件zipFile, err : os.Create("test.zip")if err ! nil {panic(err)}defer zipFile.Close()// 创建一个新的 *Writer 对象zipWriter : zip.NewWriter(zipFile)defer zipWriter.Close()// 创…...

一图解千言,了解常见的流程图类型及其作用

在企业管理、软件研发过程中&#xff0c;经常会需要进行各种业务流程梳理&#xff0c;而流程图就是梳理业务时必要的手段&#xff0c;同时也是梳理的产出。但在不同的情况下适用的流程图又不尽相同。 本文我们就一起来总结一下8 种最常见的流程图类型 数据流程图 数据流程图&…...

【微信小程序_19_自定义组件(1)】

摘要:本文主要介绍了小程序开发中自定义组件的相关知识。包括组件的创建与引用,可在项目根目录创建组件文件夹,生成相应文件,并根据使用频率选择全局或局部引用。还阐述了组件和页面的区别,如组件的.json 文件需声明 “component: true”,.js 文件调用 Component () 函数…...

标准版admin后台页面添加及开发操作流程及注意事项

基础介绍 CRMEB后台管理是基于vue2技术栈进行开发搭建的 Vue Router 使用的是v3版本&#xff0c;mode为history模式 如需修改 mode 请在src/setting.js中修改routerMode 新建页面 新建路由 根据目录结构&#xff0c;需要在src/router/modules中对应模块中&#xff0c;添加对…...

‘perl‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

‘perl’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 明明已经根据教程安装了perl环境,但是在cmd中依赖报该错误,本章教程提供解决办法。 一、激活perl环境 state shell ActiveState-Perl-5.36.0此时输入perl -v 是可以直接输出perl版本号的。 二、找到perl的执…...

如何利用CMMI帮助组织消除低价值流程

CMMI发展到今天&#xff0c;过程中历经了不断的蜕变和升级。从早期的CMM到今天的CMMI3.0&#xff0c;从早期的22个过程域优化组合到今天的20个实践域&#xff0c;从早期隶属的SEI到今天的CMMI研究院&#xff0c;所有的变化都是与时俱进&#xff0c;都是为了提供更好的实践&…...

如何理解线程安全这个概念?

文章目录 为什么需要线程安全&#xff1f;线程安全的实现方式总结推荐阅读文章 线程安全&#xff08;Thread Safety&#xff09;是指在多线程环境中&#xff0c;多个线程同时访问某个对象时&#xff0c;不会导致程序出现错误的状态或不一致的结果。简单来说&#xff0c;线程安全…...

代码随想录算法训练营第48天| 739. 每日温度,496.下一个更大元素 I,503.下一个更大元素II

第十一章&#xff1a;图论part01 图论理论基础 大家可以在看图论理论基础的时候&#xff0c;很多内容 看不懂&#xff0c;例如也不知道 看完之后 还是不知道 邻接矩阵&#xff0c;邻接表怎么用&#xff0c; 别着急。 理论基础大家先对各个概念有个印象就好&#xff0c;后面在…...

Qt 支持打包成安卓

1. 打开维护Qt&#xff0c;双击MaintenanceTool.exe 2.登陆进去,默认是添加或移除组件&#xff0c;点击下一步&#xff0c; 勾选Android, 点击下一步 3.更新安装中 4.进度100%&#xff0c;完成安装&#xff0c;重启。 5.打开 Qt Creator&#xff0c;编辑-》Preferences... 6.进…...

PDF工具类源码

PDF-Guru: PDF Guru Anki是一款以PDF为中心的多功能办公学习工具箱软件&#xff0c;包含四大板块功能&#xff1a;PDF实用工具箱、Anki制卡神器、Anki最强辅助、视频笔记神器&#xff0c;软件功能众多且强大&#xff0c;熟练运用可以大幅提高办公和学习效率&#xff0c;绝对是您…...

NirCmd-Gui-Chinese-Introduction

简介 此程序是我的一个练习作品&#xff0c;单纯是为了提升编程水平&#xff0c;次要是为了做一个NirCmd的Gui&#xff0c;其实主要成分还是Gui&#xff0c;核心代码就两三行。 主要是Gui&#xff0c;功能基于nircmd.exe实现&#xff0c;程序本身不提供一些重要的功能。 关于…...

吴恩达深度学习笔记(7)

误差分析&#xff1a; 你运行一个算法代替人类计算&#xff0c;但是没有达到人类的效果&#xff0c;需要手动检查算法中的错误&#xff0c;对模型的一些部分做相应调整&#xff0c;才能更好地提升分类的精度。如果不加分析去做&#xff0c;可能几个月的努力对于提升精度并没有…...

二、数据离线处理场景化解决方案

https://connect.huaweicloud.com/courses/learn/Learning/sp:cloudEdu_?courseNocourse-v1:HuaweiXCBUCNXE147Self-paced&courseType1 1.离线处理方案 **业务场景-安平领域** 业务场景-金融领域 离线批处理常用组件 HDFS&#xff1a;分布式文件系统&#xff0c;为各种…...

算法题总结(十四)——贪心算法(上)

贪心算法 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心的套路&#xff08;什么时候用贪心&#xff09; 刷题或者面试的时候&#xff0c;手动模拟一下感觉可以局部最优推出整体最优&#xff0c;而且想不到反例&#xff0c;那么就试一试…...

hive on tez 指定队列后任务一直处于running状态

如上图所示一直处于running状态&#xff0c;查看日志发现一直重复弹出同一个info&#xff1a; 2024-10-18 16:57:32,739 [INFO] [AMRM Callback Handler Thread] |rm.YarnTaskSchedulerService|: Allocated: <memory:0, vCores:0> 释义: 当前应用程序没有分配到任何内存…...

闲说视频清晰度和各种格式、编码技术的发展历史

文章目录 引子清晰度视频格式&#xff1a;MP4、AVI 、MKV、MOV、WMV、FLV 、RMVB等等什么是视频格式MP4AVIMKVMOVWMVFLVRM / RMVB其他 编码技术&#xff1a;MPEG-1、MPEG-2、MPEG-4、RealVideo、DivX、XviD、H.264&#xff08;AVC&#xff09;、H.265&#xff08;HEVC&#xff…...

嵌入式职业规划

嵌入式职业规划 在嵌入式的软件开发中&#xff0c;可以分为&#xff1a; 嵌入式MCU软件开发工程师&#xff1b; 嵌入式Linux底层&#xff08;BSP&#xff09;软件开发工程师&#xff1b; 嵌入式Linux应用开发工程师&#xff1b; 嵌入式FPGA算法开发工程师 对于前两个阶段 …...

Nginx - 实现 TCP/DUP流量的按 IP 动态转发

文章目录 需求背景需求目标&#xff1a;使用场景&#xff1a;成功标准&#xff1a;技术要求&#xff1a; Ng配置测试验证 需求 Nginx Stream TCP 协议按 IP 转发 背景 为了优化网络性能和提升服务的可用性&#xff0c;我们需要在 Nginx 中配置 stream 模块&#xff0c;使其根…...

基于深度学习的进化神经网络设计

基于深度学习的进化神经网络设计&#xff08;Evolutionary Neural Networks, ENNs&#xff09;结合了进化算法&#xff08;EA&#xff09;和神经网络&#xff08;NN&#xff09;的优点&#xff0c;用于自动化神经网络架构的设计和优化。通过模拟自然进化的选择、变异、交叉等过…...

软考-软件设计师(10)-专业英语词汇汇总与新技术知识点

场景 以下为高频考点、知识点汇总。 软件设计师上午选择题知识点、高频考点、口诀记忆技巧、经典题型汇总: 软考-软件设计师(1)-计算机基础知识点:进制转换、数据编码、内存编址、串并联可靠性、海明校验码、吞吐率、多媒体等: 软考-软件设计师(1)-计算机基础知识点:进制…...

PyTorch 2.5 发布带来一些新特性和改进

官网&#xff1a;https://github.com/pytorch/pytorchGitHub&#xff1a;https://github.com/pytorch/pytorch原文&#xff1a;https://github.com/pytorch/pytorch/releases/tag/v2.5.0 主要亮点 (Highlights)] SDPA CuDNN 后端&#xff1a;为 torch.nn.functional.scaled_d…...