oracle java 并发_【转】JAVA并发教程(ORACLE官网资料)

本文是Oracle官方的Java并发相关的教程,感谢并发编程网的翻译和投递。

计算机的使用者一直以为他们的计算机可以同时做很多事情。他们认为当其他的应用程序在下载文件,管理打印队列或者缓冲音频的时候他们可以继续在文字处理程序上工作。甚至对于单个应用程序,他们任然期待它能在在同一时间做很多事情。举个例子,一个流媒体播放程序必须能同时完成以下工作:从网络上读取数字音频,解压缩数字音频,管理播放和更新程序显示。甚至文字处理器也应该能在忙于重新格式化文本和刷新显示的情况下同时响应键盘和鼠标事件。这样的软件就被称为并发软件。

通过Java语言和Java类库对于基础并发的支持,Java平台具有完全(from the ground up )支持并发编程的能力。从JDK5.0起,Java平台还引入了高级并发APIs。这个课程不仅涵盖了Java平台基础并发内容,还对高级并发APIs有一定的阐述。

进程和线程

(本部分原文链接,译文链接,译者:bjsuo,校对:郑旭东)

在并发编程中,有两个基本的执行单元:进程和线程。在java语言中,并发编程最关心的是线程,然而,进程也是非常重要的。

即使在只有单一的执行核心的计算机系统中,也有许多活动的进程和线程。因此,在任何给定的时刻,只有一个线程在实际执行。处理器的处理时间是通过操作系统的时间片在进程和线程中共享的。

现在具有多处理器或有多个执行内核的多处理器的计算机系统越来越普遍,这大大增强了系统并发执行的进程和线程的吞吐量–但在不没有多个处理器或执行内核的简单的系统中,并发任然是可能的。

进程

进程具有一个独立的执行环境。通常情况下,进程拥有一个完整的、私有的基本运行资源集合。特别地,每个进程都有自己的内存空间。

进程往往被看作是程序或应用的代名词,然而,用户看到的一个单独的应用程序实际上可能是一组相互协作的进程集合。为了便于进程之间的通信,大多数操作系统都支持进程间通信(IPC),如pipes 和sockets。IPC不仅支持同一系统上的通信,也支持不同的系统。

Java虚拟机的大多数实现是单进程的。Java应用可以使用的ProcessBuilder对象创建额外的进程,多进程应用超出了本课的范围。

线程

线程有时也被称为轻量级的进程。进程和线程都提供了一个执行环境,但创建一个新的线程比创建一个新的进程需要的资源要少。

线程是在进程中存在的 — 每个进程最少有一个线程。线程共享进程的资源,包括内存和打开的文件。这样提高了效率,但潜在的问题就是线程间的通信。

多线程的执行是Java平台的一个基本特征。每个应用都至少有一个线程 – 或几个,如果算上“系统”线程的话,比如内存管理和信号处理等。但是从程序员的角度来看,启动的只有一个线程,叫主线程。这个线程有能力创建额外的线程,我们将在下一节演示。

线程对象

(本部分原文链接,译文链接,译者:郑旭东)

在Java中,每个线程都是Thread类的实例。并发应用中一般有两种不同的线程创建策略。

直接控制线程的创建和管理,每当应用程序需要执行一个异步任务的时候就为其创建一个线程

将线程的管理从应用程序中抽象出来作为执行器,应用程序将任务传递给执行器,有执行器负责执行。

这一节,我们将讨论Thread对象,有关Executors将在高级并发对象一节中讨论。

定义并启动一个线程

应用程序在创建一个线程实例时,必须提供需要在线程中运行的代码。有两种方式去做到这一点:

提供一个Runnable对象。Runnable对象仅包含一个run()方法,在这个方法中定义的代码将在会线程中执行。将Runnable对象传递给Thread类的构造函数即可,如下面这个HelloRunnable的例子:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public class HelloRunnable implementsRunnable {2

3 public voidrun() {4 System.out.println("Hello from a thread!");5 }6

7 public static voidmain(String args[]) {8 (new Thread(newHelloRunnable())).start();9 }10

11 }

View Code

继承Thread类。Thread类自身已实现了Runnable接口,但它的run()方法中并没有定义任何代码。应用程序可以继承与Thread类,并复写run()方法。如例子HelloThread

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public class HelloThread extendsThread {public voidrun() {

System.out.println("Hello from a thread!");

}public static voidmain(String args[]) {

(newHelloThread()).start();

}

}

View Code

需要注意的是,上述两个例子都需要调用Thread.start()方法来启动一个新的线程。 哪一种方式是我们应该使用的?相对来说,第一种更加通用,因为Runnable对象可以继承于其他类(Java只支持单继承,当一个类继承与Thread类后,就无法继承与其他类)。第二种方法更易于在简单的应用程序中使用,但它的局限就是:你的任务类必须是Thread的子类。这个课程更加聚焦于第一种将Runnable任务和Thread类分离的方式。不仅仅是因为这种方式更加灵活,更因为它更适合后面将要介绍的高级线程管理API。 Thread类定义了一些对线程管理十分有用的的方法。在这些方法中,有一些静态方法可以给当前线程调用,它们可以提供一些有关线程的信息,或者影响线程的状态。而其他一些方法可以由其他线程进行调用,用于管理线程和Thread对象。我们将在下面的章节中,深入探讨这些内容。

使用Sleep方法暂停一个线程

使用Thread.sleep()方法可以暂停当前线程一段时间。这是一种使处理器时间可以被其他线程或者运用程序使用的有效方式。sleep()方法还可以用于调整线程执行节奏(见下面的例子)和等待其他有执行时间需求的线程(这个例子将在下一节演示)。

在Thread中有两个不同的sleep()方法,一个使用毫秒表示休眠的时间,而另一个是用纳秒。由于操作系统的限制休眠时间并不能保证十分精确。休眠周期可以被interrups所终止,我们将在后面看到这样的例子。不管在任何情况下,我们都不应该假定调用了sleep()方法就可以将一个线程暂停一个十分精确的时间周期。

SleepMessages程序为我们展示了使用sleep()方法每四秒打印一个信息的例子

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classSleepMessages {public static voidmain(String args[])throwsInterruptedException {

String importantInfo[]={"Mares eat oats","Does eat oats","Little lambs eat ivy","A kid will eat ivy too"};for (int i = 0;

i

i++) {//Pause for 4 seconds

Thread.sleep(4000);//Print a message

System.out.println(importantInfo[i]);

}

}

}

View Code

main()方法声明了它有可能抛出InterruptedException。当其他线程中断当前线程时,sleep()方法就会抛出该异常。由于这个应用程序并没有定义其他的线程,所以并不用关心如何处理该异常。

中断(Interrupts)

中断是给线程的一个指示,告诉它应该停止正在做的事并去做其他事情。一个线程究竟要怎么响应中断请求取决于程序员,不过让其终止是很普遍的做法。这是本文重点强调的用法。

一个线程通过调用对被中断线程的Thread对象的interrupt()方法,发送中断信号。为了让中断机制正常工作,被中断的线程必须支持它自己的中断(即要自己处理中断)

中断支持

线程如何支持自身的中断?这取决于它当前正在做什么。如果线程正在频繁调用会抛InterruptedException异常的方法,在捕获异常之后,它只是从run()方法中返回。例如,假设在SleepMessages的例子中,关键的消息循环在线程的Runnable对象的run方法中,代码可能会被修改成下面这样以支持中断:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

for (int i = 0; i < importantInfo.length; i++) {//Pause for 4 seconds

try{

Thread.sleep(4000);

}catch(InterruptedException e) {//We've been interrupted: no more messages.

return;

}//Print a message

System.out.println(importantInfo[i]);

}

View Code

许多会抛InterruptedException异常的方法(如sleep()),被设计成接收到中断后取消它们当前的操作,并在立即返回。

如果一个线程长时间运行而不调用会抛InterruptedException异常的方法会怎样? 那它必须周期性地调用Thread.interrupted()方法,该方法在接收到中断请求后返回true。例如:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

for (int i = 0; i < inputs.length; i++) {

heavyCrunch(inputs[i]);if(Thread.interrupted()) {//We've been interrupted: no more crunching.

return;

}

}

View Code

在这个简单的例子中,代码只是检测中断,并在收到中断后退出线程。在更复杂的应用中,抛出一个InterruptedException异常可能更有意义。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

if(Thread.interrupted()){throw newInterruptedException();

}

View Code

这使得中断处理代码能集中在catch语句中。

中断状态标记

中断机制通过使用称为中断状态的内部标记来实现。调用Thread.interrupt()设置这个标记。当线程通过调用静态方法Thread.interrupted()检测中断时,中断状态会被清除。非静态的isInterrupted()方法被线程用来检测其他线程的中断状态,不改变中断状态标记。

按照惯例,任何通过抛出一个InterruptedException异常退出的方法,当抛该异常时会清除中断状态。不过,通过其他的线程调用interrupt()方法,中断状态总是有可能会立即被重新设置。

Joins

Join()方法可以让一个线程等待另一个线程执行完成。若t是一个正在执行的Thread对象,

t.join();

将会使当前线程暂停执行并等待t执行完成。重载的join()方法可以让开发者自定义等待周期。然而,和sleep()方法一样join()方法依赖于操作系统的时间处理机制,你不能假定join()方法将会精确的等待你所定义的时长。

如同sleep()方法,join()方法响应中断并在中断时抛出InterruptedException。

一个简单的线程例子

下面这个简单的例子将会把这一节的一些概念放到一起演示。SimpleThreads程序有两个线程组成,第一个是主线程,它从创建了一个线程并等待它执行完成。如果MessageLoop线程执行了太长时间,主线程将会将其中断。

MessageLoop现场将会打印一系列的信息。如果中断在它打印完所有信息前发生,它将会打印一个特定的消息并退出。

public classSimpleThreads {//Display a message, preceded by//the name of the current thread

static voidthreadMessage(String message) {

String threadName=Thread.currentThread().getName();

System.out.format("%s: %s%n",

threadName,

message);

}private static classMessageLoopimplementsRunnable {public voidrun() {

String importantInfo[]={"Mares eat oats","Does eat oats","Little lambs eat ivy","A kid will eat ivy too"};try{for (int i = 0;

i

i++) {//Pause for 4 seconds

Thread.sleep(4000);//Print a message

threadMessage(importantInfo[i]);

}

}catch(InterruptedException e) {

threadMessage("I wasn't done!");

}

}

}public static voidmain(String args[])throwsInterruptedException {//Delay, in milliseconds before//we interrupt MessageLoop//thread (default one hour).

long patience = 1000 * 60 * 60;//If command line argument//present, gives patience//in seconds.

if (args.length > 0) {try{

patience= Long.parseLong(args[0]) * 1000;

}catch(NumberFormatException e) {

System.err.println("Argument must be an integer.");

System.exit(1);

}

}

threadMessage("Starting MessageLoop thread");long startTime =System.currentTimeMillis();

Thread t= new Thread(newMessageLoop());

t.start();

threadMessage("Waiting for MessageLoop thread to finish");//loop until MessageLoop//thread exits

while(t.isAlive()) {

threadMessage("Still waiting...");//Wait maximum of 1 second//for MessageLoop thread//to finish.

t.join(1000);if (((System.currentTimeMillis() - startTime) >patience)&&t.isAlive()) {

threadMessage("Tired of waiting!");

t.interrupt();//Shouldn't be long now//-- wait indefinitely

t.join();

}

}

threadMessage("Finally!");

}

}

同步

(本部分原文链接,译文链接,译者:蘑菇街-小宝,Greenster,李任校对:丁一,郑旭东,李任)

线程间的通信主要是通过共享域和引用相同的对象。这种通信方式非常高效,不过可能会引发两种错误:线程干扰和内存一致性错误。防止这些错误发生的方法是同步。

不过,同步会引起线程竞争,当两个或多个线程试图同时访问相同的资源,随之就导致Java运行时环境执行其中一个或多个线程比原先慢很多,甚至执行被挂起,这就出现了线程竞争。线程饥饿和活锁都属于线程竞争的范畴。关于线程竞争的更多信息可参考活跃度一节。

本节内容包括以下这些主题:

线程干扰讨论了当多个线程访问共享数据时错误是怎么发生的。

内存一致性错误讨论了不一致的共享内存视图导致的错误。

同步方法讨论了 一种能有效防止线程干扰和内存一致性错误的常见做法。

内部锁和同步讨论了更通用的同步方法,以及同步是如何基于内部锁实现的。

原子访问讨论了不能被其他线程干扰的操作的总体思路。

1.  线程干扰

下面这个简单的Counter类:

classCounter {private int c = 0;public voidincrement() {

c++;

}public voiddecrement() {

c--;

}public intvalue() {returnc;

}

}

Counter类被设计成:每次调用increment()方法,c的值加1;每次调用decrement()方法,c的值减1。如果当同一个Counter对象被多个线程引用,线程间的干扰可能会使结果同我们预期的不一致。

当两个运行在不同的线程中却作用在相同的数据上的操作交替执行时,就发生了线程干扰。这意味着这两个操作都由多个步骤组成,而步骤间的顺序产生了重叠。

Counter类实例的操作会交替执行,这看起来似乎不太可能,因为c上的这两个操作都是单一而简单的语句。然而,即使一个简单的语句也会被虚拟机转换成多个步骤。我们不去深究虚拟机内部的详细执行步骤——理解c++这个单一的语句会被分解成3个步骤就足够了:

获取当前c的值;

对获取到的值加1;

把递增后的值写回到c;

语句c–也可以按同样的方式分解,除了第二步的操作是递减而不是递增。

假设线程A调用increment()的同时线程B调用decrement().如果c的初始值为0,线程A和B之间的交替执行顺序可能是下面这样:

线程A:获取c;

线程B:获取c;

线程A:对获取的值加1,结果为1;

线程B:对获取的值减1,结果为-1;

线程A:结果写回到c,c现在是1;

线程B:结果写回到c,c现在是-1;

线程A的结果因为被线程B覆盖而丢失了。这个交替执行的结果只是其中一种可能性。在不同的环境下,可能是线程B的结果丢失了,也可能是不会出任何问题。由于结果是不可预知的,所以线程干扰的bug很难检测和修复。

2.  内存一致性错误

当不同的线程对相同的数据产生不一致的视图时会发生内存一致性错误。内存一致性错误的原因比较复杂,也超出了本教程的范围。不过幸运的是,一个程序员并不需要对这些原因有详细的了解。所需要的是避免它们的策略。

避免内存一致性错误的关键是理解happens-before关系。这种关系只是确保一个特定语句的写内存操作对另外一个特定的语句可见。要说明这个问题,请参考下面的例子。假设定义和初始化了一个简单int字段:

int counter =0 ;

这个counter字段被A,B两个线程共享。假设线程A对counter执行递增:

counter++;

然后,很快的,线程B输出counter:

System.out.println(counter);

如果这两个语句已经在同一个线程中被执行过,那么输出的值应该是“1”。不过如果这两个语句在不同的线程中分开执行,那输出的值很可能是“0”,因为无法保证线程A对counter的改动对线程B是可见的——除非我们在这两个语句之间已经建立了happens-before关系。

有许多操作会建立happens-before关系。其中一个是同步,我们将在下面的章节中看到。

我们已经见过两个建立happens-before关系的操作。

当一条语句调用Thread.start方法时,和该语句有happens-before关系的每一条语句,跟新线程执行的每一条语句同样有happens-before关系。创建新线程之前的代码的执行结果对线新线程是可见的。

当一个线程终止并且当导致另一个线程中Thread.join返回时,被终止的线程执行的所有语句和在join返回成功之后的所有语句间有happens-before关系。线程中代码的执行结果对执行join操作的线程是可见的。

要查看建立happens-before关系的操作列表,请参阅java.util.concurrent包的摘要页面。

3.  同步方法

Java编程语言提供两种同步方式:同步方法和同步语句。相对较复杂的同步语句将在下一节中介绍。本节主要关注同步方法。

要让一个方法成为同步方法,只需要在方法声明中加上synchronized关键字:

public classSynchronizedCounter {private int c = 0;public synchronized voidincrement() {

c++;

}public synchronized voiddecrement() {

c--;

}public synchronized intvalue() {returnc;

}

}

如果count是SynchronizedCounter类的实例,那么让这些方法成为同步方法有两个作用:

首先,相同对象上的同步方法的两次调用,它们要交替执行是不可能的。 当一个线程正在执行对象的同步方法时,所有其他调用该对象同步方法的线程会被阻塞(挂起执行),直到第一个线程处理完该对象。

其次,当一个同步方法退出时,它会自动跟该对象同步方法的任意后续调用建立起一种happens-before关系。这确保对象状态的改变对所有线程是可见的。

注意构造方法不能是同步的——构造方法加synchronized关键字会报语法错误。同步的构造方法没有意义,因为当这个对象被创建的时候,只有创建对象的线程能访问它。

警告:当创建的对象会被多个线程共享时必须非常小心,对象的引用不要过早“暴露”出去。比如,假设你要维护一个叫instances的List,它包含类的每一个实例对象。你可能会尝试在构造方法中加这样一行:

instances.add(this);

不过其他线程就能够在对象构造完成之前使用instances访问对象。

同步(synchronized)方法使用一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,对象域上的所有读写操作都是通过synchronized方法来完成的。(一个重要的例外:final域,在对象被创建后不可修改,能被非synchronized方法安全的读取)。synchronized同步策略很有效,不过会引起活跃度问题,我们将在本节后面看到。

4.  内部锁与同步

同步机制的建立是基于其内部一个叫内部锁或者监视锁的实体。(在Java API规范中通常被称为监视器。)内部锁在同步机制中起到两方面的作用:对一个对象的排他性访问;建立一种happens-before关系,而这种关系正是可见性问题的关键所在。

每个对象都有一个与之关联的内部锁。通常当一个线程需要排他性的访问一个对象的域时,首先需要请求该对象的内部锁,当访问结束时释放内部锁。在线程获得内部锁到释放内部锁的这段时间里,我们说线程拥有这个内部锁。那么当一个线程拥有一个内部锁时,其他线程将无法获得该内部锁。其他线程如果去尝试获得该内部锁,则会被阻塞。

当线程释放一个内部锁时,该操作和对该锁的后续请求间将建立happens-before关系。

5.  同步方法中的锁

当线程调用一个同步方法时,它会自动请求该方法所在对象的内部锁。当方法返回结束时则自动释放该内部锁,即使退出是由于发生了未捕获的异常,内部锁也会被释放。

你可能会问调用一个静态的同步方法会如何,由于静态方法是和类(而不是对象)相关的,所以线程会请求类对象(Class Object)的内部锁。因此用来控制类的静态域访问的锁不同于控制对象访问的锁。

6.  同步块

另外一种同步的方法是使用同步块。和同步方法不同,同步块必须指定所请求的是哪个对象的内部锁:

public voidaddName(String name) {synchronized(this) {

lastName=name;

nameCount++;

}

nameList.add(name);

}

在上面的例子中,addName方法需要使lastName和nameCount的更改保持同步,而且要避免同步调用该对象的其他方法。(在同步代码中调用其他方法会产生Liveness一节所描述的问题。)如果不使用同步块,那么必须要定义一个额外的非同步方法,而这个方法仅仅是用来调用nameList.add。

使用同步块对于更细粒度的同步很有帮助。例如类MsLunch有两个实例域c1和c2,他们并不会同时使用(译者注:即c1和c2是彼此无关的两个域),所有对这两个域的更新都需要同步,但是完全不需要防止c1的修改和c2的修改相互之间干扰(这样做只会产生不必要的阻塞而降低了并发性)。这种情况下不必使用同步方法,可以使用和this对象相关的锁。这里我们创建了两个“锁”对象(译者注:起到加锁效果的普通对象lock1和lock2)。

public classMsLunch {private long c1 = 0;private long c2 = 0;private Object lock1 = newObject();private Object lock2 = newObject();public voidinc1() {synchronized(lock1) {

c1++;

}

}public voidinc2() {synchronized(lock2) {

c2++;

}

}

}

使用这种方法时要特别小心,需要十分确定c1和c2是彼此无关的域。

7.  可重入同步

还记得吗,一个线程不能获得其他线程所拥有的锁。但是它可以获得自己已经拥有的锁。允许一个线程多次获得同一个锁实现了可重入同步。这里描述了一种同步代码的场景,直接的或间接地,调用了一个也拥有同步代码的方法,且两边的代码使用的是同一把锁。如果没有这种可重入的同步机制,同步代码则需要采取许多额外的预防措施以防止线程阻塞自己。

8.  原子访问

在编程过程中,原子操作是指所有操作都同时发生。原子操作不能被中途打断:要么全做,要么不做。原子操作在完成前不会有看得见的副作用。

我们发现像c++这样的增量表达式,并没有描述原子操作。即使是非常简单的表达式也能够定义成能被分解为其他操作的复杂操作。然而,有些操作你可以定义为原子的:

对引用变量和大部分基本类型变量(除long和double之外)的读写是原子的。

对所有声明为volatile的变量(包括long和double变量)的读写是原子的。

原子操作不会交错,于是可以放心使用,不必担心线程干扰。然而,这并不能完全消除原子操作上的同步,因为内存一致性错误仍可能发生。使用volatile变量可以降低内存一致性错误的风险,因为对volatile变量的任意写操作,对于后续在该变量上的读操作建立了happens-before关系。这意味着volatile变量的修改对于其他线程总是可见的。更重要的是,这同时也意味着当一个线程读取一个volatile变量时,它不仅能看到该变量最新的修改,而且也能看到致使该改变发生的代码的副效应。

使用简单的原子变量访问比通过同步代码来访问更高效,但是需要程序员更加谨慎以避免内存一致性错误。至于这额外的付出是否值得,得看应用的大小和复杂度。

java.util.concurrent包中的一些类提供了一些不依赖同步机制的原子方法。我们将在高级并发对象这一节中讨论它们。

活跃度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/347731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署Spring Boot Angular App(Maven和Tomcat)的4种方法

在上一篇有关Spring Boot angular 5的文章中 &#xff0c;我们使用Spring Boot angular 5实现了一个完整的堆栈端到端Web应用程序。在本文中&#xff0c;我们将讨论在tomcat上部署Spring Boot和Angle App的不同方法。 我们将创建一个具有后端&#xff08;服务器&#xff09;和前…

计算机二级web题目(8.3)--简单应用题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1.在考生文件夹下的Web3目录中&#xff0c;存有3.htm文件&#xff0c;该文件不完…

计算机二级web题目(8.4)--综合应用题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1.在考生文件夹下的Web5目录中&#xff0c;存有5.htm文件&#xff0c;该文件不完…

(3.5)HarmonyOS鸿蒙上下左右方向滑动

需要获取按下时候的坐标和松开时候的坐标&#xff0c;并将两者进行比较。 ①MainAbilitySlice.java文件 可以根据使用情况做修改代码中判断处的限制偏差范围。 package com.example.yeman.slice;import com.example.yeman.ResourceTable; import ohos.aafwk.ability.Ability…

sql 注射_基本注射/资格赛,范围

sql 注射这是上周解决的DI / CDI基础知识的延续-在本文中&#xff0c;我将讨论基础注入&#xff0c;限定词和范围。 在上一个主题中&#xff0c;我们提供了有关DI / CDI概念的大量信息&#xff0c;我们还讨论了如何使用注释加载这些bean或类-这构成了对象的组成并创建了关于如…

计算机二级web题目(9.1)--综合选择题3

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1下列叙述中正确的是(D)。 A、栈是"先进先出"的线性表 B、队列是"…

java小程序 2048_微信小程序之游戏2048

主要用来锻炼逻辑思维能力image.png可以选模式image.png这里面主要解决的问题是&#xff1a;1.判断滑动方向//在滑动块级绑定滑动开始和滑动结束的方法很原始的方法&#xff0c;startFn时保存开始的(x,y),endFn时保存结束的(x1,y2),根据这四个参数 判断方向&#xff0c;算法在方…

Java面向对象(8)--继承性

多个类中存在相同属性和行为时&#xff0c;可以将这些内容抽取到单独一个类中&#xff0c;那么多个类无需再定义这些相同的属性和行为&#xff0c;只要继承那个类即可。 这里的多个类称为子类(派生类)&#xff0c;单独的这个类称为父类(基类或超类)。 语法格式&#xff1a;cla…

aimesh node重启_华硕 RT-AC86U 和 网件 R7000 组 AiMesh 成功

家里之前买了一个 R7000 主路由器&#xff0c;后来我嫌我房间里的信号有点烂( 5G 信号只能 2 格&#xff0c;网速比 2.4G 还慢)&#xff0c;所以就入手了一个华硕 RT-AC86U 作为主路由器&#xff0c;R7000 则作为 AP。在买的时候就想组 AiMesh&#xff0c;但是因为种种事情耽搁…

maven ant_如何在Maven中运行Ant目标?

maven antmaven-antrun-plugin允许我们在各种maven构建阶段中运行ant目标。 我将专门为具有开发环境的开发人员解释maven-antrun-plugin的非常实际的用法。 通常&#xff0c;使用maven build&#xff0c;您会将项目捆绑到war文件或ear文件中。 您可以使用maven-antrun-plugin…

java中打开文件显示_在默认文件资源管理器中打开文件,并使用JavaFX或普通Java突出显示它...

我想做标题所说的.部分解决方案例如,在Windows中,您可以使用以下代码在默认资源管理器中打开文件并突出显示它.(虽然它需要修改包含空格的文件)&#xff1a;/*** Opens the file with the System default file explorer.** param path the path*/public static void openFileLo…

win10下vscode配置c语言环境

1、C编译器下载 C编译器&#xff08;MinGW-W64 GCC&#xff09;的下载&#xff1a;点击官方下载 或者点击网盘下载提取码为karj 下载完成后解压&#xff0c;将解压后的文件夹放到合适的位置&#xff0c;点开其bin子文件夹&#xff0c;复制路径。 2、win10下环境变量配置 ①…

Java面向对象(11)--多态性

父类 变量名 new 子类&#xff08;&#xff09;&#xff1b;对象的多态性&#xff1a;父类的引用指向子类的对象 Java引用变量有两个类型&#xff1a;编译时类型和运行时类型。编译时类型由声明 该变量时使用的类型决定&#xff0c;运行时类型由实际赋给该变量的对象决定。简…

Java面向对象(12)--对象类型转换 (Casting )

基本数据类型的Casting&#xff1a; ①自动类型转换&#xff1a;小的数据类型可以自动转换成大的数据类型 如long g20; double d12.0f ②强制类型转换&#xff1a;可以把大的数据类型强制转换(casting)成小的数据类型 如 float f(float)12.0; int a(int)1200L Java对象的强制…

知识蒸馏 循环蒸馏_Java垃圾收集蒸馏

知识蒸馏 循环蒸馏串行&#xff0c;并行&#xff0c;并发&#xff0c;CMS&#xff0c;G1&#xff0c;Young Gen&#xff0c;New Gen&#xff0c;Old Gen&#xff0c;Perm Gen&#xff0c;Eden&#xff0c;Tenured&#xff0c;Survivor Spaces&#xff0c;Safepoints和数百个JVM…

Javascript中的AES加密和Java中的解密

AES代表高级加密系统&#xff0c;它是一种对称加密算法&#xff0c;很多时候我们需要在客户端加密一些纯文本&#xff08;例如密码&#xff09;并将其发送到服务器&#xff0c;然后由服务器解密以进行进一步处理.AES加密和解密更加容易在相同的平台&#xff08;例如Android客户…

Java面向对象(14)--包装类的使用

针对八种基本数据类型定义相应的引用类型—包装类&#xff08;封装类&#xff09;&#xff0c;有了类的特点&#xff0c;就可以调用类中的方法。 基本数据类型 <——> 包装类&#xff0c;String——>包装类 ①装 int num 9; Integer int1 new Integer(num); Syste…

资源泄漏如何处理_处理缓慢的资源泄漏

资源泄漏如何处理使用Java监视器查找资源泄漏 查找缓慢的资源泄漏是使应用程序服务器长时间保持正常运行的关键。 在这里&#xff0c;我解释了如何使用Java监视器来发现缓慢的资源泄漏&#xff0c;以及如何验证它们是否是实际泄漏&#xff0c;而不仅仅是额外的预分配到某些HTTP…

mac php 超时,PHP---Mac上开启php错误提示

发现在使用mac 上 PHP开发项目的时候&#xff0c;程序代码错误的时候没有错误提示&#xff0c;只是提示白板。研究和查找资料才调整了一下; 步骤如下&#xff1a;1.找到php.ini文件如图所示&#xff1a;1)找到 display_errors Off &#xff0c;把Off 改为 On . 最后为 display…

tomcat 轮询_用Spring长轮询Tomcat

tomcat 轮询就像喜剧演员弗兰基 豪威尔 &#xff08; Frankie Howerd&#xff09;所说的“噢&#xff0c;小姐小姐” &#xff0c;但足够多的英国影射和双重诱惑&#xff0c;因为长轮询Tomcat对隔壁的闷气不是某种性的偏见&#xff0c;这是一种技术&#xff08;或更像是一种hac…