Java多线程面试题(面试必备)-程序员宅基地

技术标签: 面试  java  Java面试题  编程语言  操作系统  多线程  

能力有限,初级菜,多线程可是一块庞大的知识块,慢慢总结吧!

文章目录

一、多线程基础基础知识

1. 并发编程

1.1 并发编程的优缺点

优点

  • 充分利用多核CPU的计算能力,通过并发编程的形式将多核CPU的计算能力发挥到极致,性能得到提升。
  • 方面进行业务的拆分。提高系统并发能力和性能:高并发系统的开发,并发编程会显得尤为重要,利用好多线程机制可以大大提高系统的并发能力及性能;面对复杂的业务模型,并行程序会比串行程序更适应业务需求,而并发编程更适合这种业务拆分。cai

缺点

  • 并发编程的目的是为了提高程序的执行效率,提高程序运行速度,但并发编程并不是总能提高性能,有时还会遇到很多问题,例如:内存泄漏,线程安全,死锁等。

1.2 并发编程的三要素

并发编程的三要素:(也是带来线程安全所在)

  1. 原子性:原子是不可再分割的最小单元,原子性是指一个或多个操作要么全部执行成功,要么全部执行失败。
  2. 可见性:一个线程对共享变量的修改,另一个线程能看到(synchronized,volatile)
  3. 有序性:程序的执行顺序按照代码的先后顺序

线程安全的问题原因有:

1. 线程切换带来的原子性问题
2. 缓存导致的可见性问题
3. 编译优化带来的有序性问题

解决方案:

  • JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
  • synchronized、volatile、LOCK,可以解决可见性问题
  • Happens-Before 规则可以解决有序性问题

1.3 并发和并行有和区别

并发:多个任务在同一个CPU上,按照细分的时间片轮流交替执行,由于时间很短,看上去好像是同时进行的。
并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的同时进行。
串行:有n个任务,由一个线程按照顺序执行。

1.4 什么是多线程,多线程的优劣?

定义:多线程是指程序中包含多个流,即在一个程序中可以同时进行多个不同的线程来执行不同的任务
优点:

  • 可以提高CPU的利用率,在多线程中,一个线程必须等待的时候,CPU可以运行其它线程而不是等待,这样就大大提高了程序的效率,也就是说单个程序可以创建多个不同的线程来完成各自的任务。
    缺点:
  • 线程也是程序,线程也需要占内存,线程也多内存也占的也多。
  • 多线程需要协调和管理,所以需要CPU跟踪线程。
  • 线程之间共享资源的访问会相互影响,必须解决禁用共享资源的问题。

2. 线程与进程

2.1 什么是线程与进程

进程:内存中运行的运用程序,每个进程都有自己独立的内存空间,一个进程可以由多个线程,例如在Windows系统中,xxx.exe就是一个进程。
线程:进程中的一个控制单元,负责当前进程中的程序执行,一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可以共享数据。

2.2 线程与进程的区别

根本区别:进程是操作系统资源分配的基本单元,而线程是处理器任务调度的和执行的基本单位。
资源开销:每个进程都有自己独立的代码和空间(程序上下文),程序之间的切换会有较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行的过程不是一条线的,而是多条线(多个线程),共同完成;线程是进程的一部分,可以把线程看作是轻量级的进程。
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。

2.3 用户线程与守护线程

用户(User)线程:运行在前台,执行具体任务,如程序的主线程,连接网络的子线程都是用户线程。
守护(Daemon)线程:运行在后台,为其它前台线程服务,也可以说守护线程是JVM非守护线程的”佣人“,一旦所有线程都执行结束,守护线程会随着JVM一起结束运行。
main函数就是一个用户线程,main函数启动时,同时JVM还启动了好多的守护线程,如垃圾回收线程,比较明显的区别时,用户线程结束,JVM退出,不管这个时候有没有守护线程的运行,都不会影响JVM的退出。

2.4 什么是线程死锁

死锁是指两个或两个以上进程(线程)在执行过程中,由于竞争资源或由于彼此通信造成的一种堵塞的现象,若无外力的作用下,都将无法推进,此时的系统处于死锁状态。
如图,线程A拥有的资源2,线程B拥有的资源1,此时线程A和线程B都试图去拥有资源1和资源2,但是它们的还在,因此就出现了死锁。
在这里插入图片描述

2.5 形成死锁的四个必要条件

  1. 互斥条件:线程(进程)对所分配的资源具有排它性,即一个资源只能被一个进程占用,直到该进程被释放。
  2. 请求与保持条件:一个进程(线程)因请求被占有资源而发生堵塞时,对已获取的资源保持不放。
  3. 不剥夺条件:线程(进程)已获取的资源在未使用完之前不能被其他线程强行剥夺,只有等自己使用完才释放资源。
  4. 循环等待条件:当发生死锁时,所等待的线程(进程)必定形成一个环路,死循环造成永久堵塞。

2.6 如何避免死锁

我们只需破坏形参死锁的四个必要条件之一即可。
破坏互斥条件:无法破坏,我们的本身就是来个线程(进程)来产生互斥
破坏请求与保持条件:一次申请所有资源
破坏不剥夺条件:占有部分资源的线程尝试申请其它资源,如果申请不到,可以主动释放它占有的资源。
破坏循环等待条件:按序来申请资源。

2.7 什么是上下文的切换

当前任务执行完,CPU时间片切换到另一个任务之前会保存自己的状态,以便下次再切换会这个任务时可以继续执行下去,任务从保存到再加载执行就是一次上下文切换。

3. 创建线程

3.1 创建线程的四种方式

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口
  4. Executors工具类创建线程池

3.2 Runnable接口和Callable接口有何区别

相同点

  1. Runnable和Callable都是接口
  2. 都可以编写多线程程序
  3. 都采用Thread.start()启动线程

不同点

  1. Runnable接口run方法无返回值,Callable接口call方法有返回值,是个泛型,和Futrue和FutureTask配合用来获取异步执行结果。
  2. Runable接口run方法只能抛出运行时的异常,且无法捕获处理;Callable接口call方法允许抛出异常,可以获取异常信息。

:Callable接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会堵塞主线程继续往下执行,如果不调用就不会堵塞。

3.2 run()方法和start()方法有和区别

每个线程都是通过某个特定的Thread对象对于的run()方法来完成其操作的,run方法称为线程体,通过调用Thread类的start方法来启动一个线程。
start()方法用于启动线程,run()方法用于执行线程的运行代码,run()可以反复调用,而start()方法只能被调用一次。

start()方法来启动一个线程,真正实现了多线程的运行。调用start()方法无需等待run()方法体代码执行结束,可以直接继续执行其它的代码;调用start()方法线程进入就绪状态,随时等该CPU的调度,然后可以通过Thread调用run()方法来让其进入运行状态,run()方法运行结束,此线程终止,然后CPU再调度其它线程。

3.3 为什么调用start()方法会执行run()方法,为什么不能直接调用run()方法

这是一个常问的面试题,new Thread,线程进入了新建的状态,start方法的作用是使线程进入就绪的状态,当分配到时间片后就可以运行了。start方法会执行线程前的相应准备工作,然后在执行run方法运行线程体,这才是真正的多线程工作。
如果直接执行了run方法,run方法会被当作一个main线程下的普通方法执行,并不会在某个线程中去执行它,所以这并不是多线程工作。
小结
调用start方法启动线程可使线程进入就绪状态,等待运行;run方法只是thread的一个普通方法调用,还是在主线程里执行。

3.4 什么是Callable和Future

Callable接口也类似于Runnable接口,但是Runnable不会接收返回值,并且无法抛出返回结果的异常,而Callable功能更强大,被线程执行后,可有返回值,这个返回值可以被Future拿到,也就是说Future可以拿到异步执行任务的返回值。
Future接口表示异步任务,是一个可能没有完成的异步任务结果,所以说Callable用于产生结果,Future用于接收结果。

3.5 什么是FutureTask

FutureTask是一个异步运算的任务,FutureTask里面可以可以传入Callable实现类作为参数,可以对异步运算任务的结果进行等待获取,判断是否已经完成,取消任务等操作。只有当结果完成之后才能取出,如果尚未完成get方法将堵塞。一个Future对象可以调用Callable和Runable的对象进行包装,由于FutureTask也是Runnable接口的实现类,所以FutureTask也可以放入线程池中。

4. 线程状态和基本操作

4.1 线程声明周期的6种状态

很多地方说线程有5种状态,但实际上是6中状态,可以参考Thread类的官方api

public enum State {
    
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

如图:
在这里插入图片描述
新创建:又称初始化状态,这个时候Thread才刚刚被new出来,还没有被启动。
可运行状态:表示已经调用Thread的start方法启动了,随时等待CPU的调度,此状态又被称为就绪状态。
被终止:死亡状态,表示已经正常执行完线程体run()中的方法了或者因为没有捕获的异常而终止run()方法了。
计时状态:调用sleep(参数)或wait(参数)后线程进入计时状态,睡眠时间到了或wait时间到了,再或者其它线程调用notify并获取到锁之后开始进入可运行状态。另一种情况,其它线程调用notify没有获取到锁或者wait时间到没有获取到锁时,进入堵塞状态。
无线等待状态:获取锁对象后,调用wait()方法,释放锁进入无线等待状态
锁堵塞状态:wait(参数)时间到或者其它线程调用notify后没有获取到锁对象都会进入堵塞状态,只要一获取到锁对象就会进入可运行状态。

堵塞状态的详解:
在这里插入图片描述

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

计算机通常只有一个CPU,在任意时刻只能执行一条机器指令,每个线程只有获取到CPU的使用权才能执行指令,所谓多线程的并发运行,其实从宏观上看,各线程轮流获取CPU的使用权,分别执行各自的任务。在运行池中,会有多个处于就绪状态的线程在等待,CPU的调度,JVM有一项任务就是负责CPU的调度,线程调度就是按照特定的机制为多个线程分配CPU的使用权。
有两种调度模型:分时调度和抢占式调度
分时调度就是让所有的线程轮流获得CPU的使用权,并且平均分配到各个线程占有CPU的时间片。
抢占式调度:Java虚拟机采用抢占式调度模型,是指优先让线程池中优先级高的线程首先占用CPU,如果线程池中优先级相同,那么随机选择一个线程,使其占有CPU,处于这个状态的CPU会一直运行,优先级高的分的CPU的时间片相对会多一点。

4.2 Java线程调度策略

线程调度优先选择优先级高的运行,但是如果出现一下情况,就会终止运行(不是进入死亡状态):

  1. 线程调用了yield方法让出CPU的使用权,线程进入就绪状态。
  2. 线程调用sleep()方法,使其进入计时状态
  3. 线程由于IO受阻
  4. 另一个更高的优先级线程出现
  5. 在支持的时间片系统中,改线程的时间片用完。

4.3 什么是线程调度(Thread Scheduler)和时间分片(Time Slicing )

线程调度是一个操作系统服务,它负责为储在Runnable状态的线程分配CPU时间片,一旦我们创建一个线程并启动它,它的执行便依赖线程调度器的实现。
时间分片是指CPU可用时间分配给Runnable的过程,分配的时间可以根据线程优先级或线程等待时间。

4.4 Java线程同步和线程调度的相关方法

  1. wait():调用后线程进入无限等待状态,并释放所持对象的锁
  2. sleep():使一个线程进入休眠状态(堵塞状态),带有对象锁,是一个静态方法,需要处理InterruptException异常。
  3. notify():唤醒一个处于等待状态的线程(无线等待或计时等待),如果多个线程在等待,并不能确切的唤醒一个线程,与JVM确定唤醒那个线程,与其优先级有关。
  4. notityAll():唤醒所有处于等待状态的线程,但是并不是将对象的锁给所有的线程,而是让它们去竞争,谁先获取到锁,谁先进入就绪状态。

4.5 sleep()和wait()有什么区别

两者都可以使线程进入等待状态

  • 类不同:sleep()是Thread下的静态方法,wait()是Object类下的方法
  • 是否释放锁:sleep()不释放锁,wait()释放锁
  • 用处不同:wait()常用于线程间的通信,sleep()常用于暂停执行。
  • 用法不同:wait()用完后,线程不会自动执行,必须调用notify()或notifyAll()方法才能执行,sleep()方法调用后,线程经过过一定时间会自动苏醒,wait(参数)也可以传参数使其苏醒。它们苏醒后还有所区别,因为wait()会释放锁,所以苏醒后没有获取到锁就进入堵塞状态,获取到锁就进入就绪状态,而sleep苏醒后之间进入就绪状态,但是如果cpu不空闲,则进入的是就绪状态的堵塞队列中。

4.6 你是如何调用wait()方法的,使用if还是循环

处以等待状态的线程可能会收到错误警告或伪唤醒,如果不在循环中检查等待条件,程序可能会在没有满足条件的时候退出。

synchronized (monitor) {
    
    //  判断条件谓词是否得到满足
    while(!locked) {
    
        //  等待唤醒
        monitor.wait();
    }
    //  处理其他的业务逻辑
}

4.7 为什么线程通信方法wait(),notify(),notifyAll()要被定义到Object类中

Java中任何对象都可以被当作锁对象,wait(),notify(),notifyAll()方法用于等待获取唤醒对象去获取锁,Java中没有提供任何对象使用的锁,但是任何对象都继承于Object类,所以定义在Object类中最合适。

有人会说,既然是线程放弃对象锁,那也可以把wait()放到Thread类中,新定义线程继承Thread类,也无需重新定义wait(),
然而,这样做有一个很大的问题,因为一个线程可以持有多把锁,你放弃一个线程时,到底要放弃哪把锁,当然了这种设计不能不能实现,只是管理起来比较麻烦。
综上:wait(),notify(),notifyAll()应该要被定义到Object类中。

4.8 为什么线程通信方法wait(),notify(),notifyAll()要在同步代码块或同步方法中被调用?

wait(),notify(),notifyAll()方法都有一个特点,就是对象去调用它们的时候必须持有锁对象。
如对象调用wait()方法后持有的锁对象就释放出去,等待下一个线程来获取。
如对象调用notifyAll()要唤醒等待中的线程,也要讲自身用于的锁对象释放,让就绪状态中的线程竞争获取锁。
由于这些方法都需要线程持有锁对象,这样只能通过同步来实现,所以它们只能在同步块或同步方法中被调用。

4.9 Thread的yiele方法有什么作用?

让出CPU的使用权,使当前线程从运行状态进入就绪状态,等待CPU的下次调度。

4.10 为什么Thread的sleep和yield是静态的?

Thread类的sleep()和yield()方法将在当前正在运行的线程上工作,所以其它处于等待状态的线程调用它们是没有意义的,所以设置为静态最合适。

4.11 线程sleep和yield方法有什么区别

  • 线程调用sleep()方法进入堵塞状态,醒来后因为(没有释放锁)后直接进入了就绪状态,运行yield后也没有释放锁,于是进入了就绪状态。
  • sleep()方法使用时需要处理InterruptException异常,而yield没有。
  • sleep()执行后进入堵塞状态(计时等待),醒来后进入就绪状态(可能是堵塞队列),而yield是直接进入就绪状态。

4.12 如何停止一个正在运行的线程?

  1. 使用stop方法终止,但是这个方法已经过期,不被推荐使用。
  2. 使用interrupt方法终止线程
  3. run方法执行结束,正常退出

4.13 如何在两个线程间共享数据?

两个线程之间共享变量即可实现共享数据。
一般来说,共享变量要求变量本身是线程安全的,然后在线程中对变量使用。

4.14 同步代码块和同步方法怎么选?

同步块是更好的选择,因为它不会锁着整个对象,当然你也可以然它锁住整个对象。同步方法会锁住整个对象,哪怕这个类中有不关联的同步块,这通常会导致停止继续执行,并等待获取这个对象锁。
同步块扩展性比较好,只需要锁住代码块里面相应的对象即可,可以避免死锁的产生。
原则:同步范围也小越好。

4.15 什么是线程安全?Servlet是线程安全吗?

线程安全是指某个方法在多线程的环境下被调用时,能够正确处理多线程之间的共享变量,能程序能够正确完成。
Servlet不是线程安全的,它是单实例多线程的,当多个线程同时访问一个方法时,不能保证共享变量是安全的。
Struts2是多实例多线程的,线程安全,每个请求过来都会new一个新的action分配这个请求,请求完成后销毁。
springMVC的controller和Servlet一样,属性单实例多线程的,不能保证共享变量是安全的。
Struts2好处是不用考虑线程安全问题,springMVC和Servlet需要考虑。
如果想既可以提升性能又可以不能管理多个对象的话建议使用ThreadLocal来处理多线程。

4.16 线程的构造方法,静态块是被哪个线程类调用的?

线程的构造方法,静态块是被哪个线程类调用的?
该线程在哪个类中被new出来,就是在哪个被哪个类调用,而run方法是线程类自身调用的。
例子:mian函数中new Thread2,Thread2中new Thread1
在这里插入图片描述
thread1线程的构造方法,静态块是thread2线程调用的,run方法是thread1调用的。
thread2线程的构造方法,静态块是main线程调用的,run方法是thread2调用的。

4.17 Java中是如何保证多线程安全的?

  1. 使用安全类,比如 java.util.concurrent 下的类,使用原子类AtomicInteger
  2. 使用自动锁,synchronized锁
  3. Lock lock = new ReentrantLock(),使用手动锁lock .lock(),lock.unlock()方法

4.18 线程同步和线程互斥的区别

线程同步:当一个线程对共享数据进行操作的时候,在没有完成相关操作时,不允许其它的线程来打断它,否则就会破坏数据的完整性,必然会引起错误信息,这就是线程同步。
线程互斥
而线程互斥是站在共享资源的角度上看问题,例如某个共享资源规定,在某个时刻只能一个线程来访问我,其它线程只能等待,知道占有的资源者释放该资源,线程互斥可以看作是一种特殊的线程同步。
实现线程同步的方法

  1. 同步代码块:sychronized(对象){} 块
  2. 同步方法:sychronized修饰的方法
  3. 使用重入锁实现线程同步:reentrantlock类的锁又互斥功能,Lock lock = new ReentrantLock(); Lock对象的ock和unlock为其加锁

4.19 你对线程优先级有什么理解?

每个线程都具有优先级的,一般来说,高优先级的在线程调度时会具有优先被调用权。我们可以自定义线程的优先级,但这并不能保证高优先级又在低优先级前被调用,只是说概率有点大。
线程优先级是1-10,1代表最低,10代表最高。
Java的线程优先级调度会委托操作系统来完成,所以与具体的操作系统优先级也有关,所以如非特别需要,一般不去修改优先级。

4.20 谈谈你对乐观锁和悲观锁的理解?

乐观锁:每个去拿数据的时候都认为别人不会修改,所以不会都不会上锁,但是在更新的时候会判断一下在此期间有没有去更新这个数据。所以乐观锁使用了多读的场合,这样可以提高吞吐量,像数据库提供的类似write_condition机制,都是用的乐观锁,还有那个原子变量类,在java.util.concurrent.atomic包下
悲观锁:总是假设最坏的情况,每次去拿数据的时候都会认为有人会修改,所以每次在拿数据的时候都会上锁。这样别的对象想拿到数据,那就必须堵塞,直到拿到锁。传统的关系型数据库用到了很多这种锁机制,比如读锁,写锁,在操作之前都会先上锁,再比如Java的同步代码块synchronized/方法用的也是悲观锁。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/JAYU_37/article/details/106321844

智能推荐

JWT(Json Web Token)实现无状态登录_无状态token登录-程序员宅基地

文章浏览阅读685次。1.1.什么是有状态?有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?服务端保存大量数据,增加服务端压力 服务端保存用户状态,无法进行水平扩展 客户端请求依赖服务.._无状态token登录

SDUT OJ逆置正整数-程序员宅基地

文章浏览阅读293次。SDUT OnlineJudge#include<iostream>using namespace std;int main(){int a,b,c,d;cin>>a;b=a%10;c=a/10%10;d=a/100%10;int key[3];key[0]=b;key[1]=c;key[2]=d;for(int i = 0;i<3;i++){ if(key[i]!=0) { cout<<key[i.

年终奖盲区_年终奖盲区表-程序员宅基地

文章浏览阅读2.2k次。年终奖采用的平均每月的收入来评定缴税级数的,速算扣除数也按照月份计算出来,但是最终减去的也是一个月的速算扣除数。为什么这么做呢,这样的收的税更多啊,年终也是一个月的收入,凭什么减去12*速算扣除数了?这个霸道(不要脸)的说法,我们只能合理避免的这些跨级的区域了,那具体是那些区域呢?可以参考下面的表格:年终奖一列标红的一对便是盲区的上下线,发放年终奖的数额一定一定要避免这个区域,不然公司多花了钱..._年终奖盲区表

matlab 提取struct结构体中某个字段所有变量的值_matlab读取struct类型数据中的值-程序员宅基地

文章浏览阅读7.5k次,点赞5次,收藏19次。matlab结构体struct字段变量值提取_matlab读取struct类型数据中的值

Android fragment的用法_android reader fragment-程序员宅基地

文章浏览阅读4.8k次。1,什么情况下使用fragment通常用来作为一个activity的用户界面的一部分例如, 一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 – 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输_android reader fragment

FFT of waveIn audio signals-程序员宅基地

文章浏览阅读2.8k次。FFT of waveIn audio signalsBy Aqiruse An article on using the Fast Fourier Transform on audio signals. IntroductionThe Fast Fourier Transform (FFT) allows users to view the spectrum content of _fft of wavein audio signals

随便推点

Awesome Mac:收集的非常全面好用的Mac应用程序、软件以及工具_awesomemac-程序员宅基地

文章浏览阅读5.9k次。https://jaywcjlove.github.io/awesome-mac/ 这个仓库主要是收集非常好用的Mac应用程序、软件以及工具,主要面向开发者和设计师。有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章《工具武装的前端开发工程师》,于是建了这么一个仓库,持续更新作为补充,搜集更多好用的软件工具。请Star、Pull Request或者使劲搓它 issu_awesomemac

java前端技术---jquery基础详解_简介java中jquery技术-程序员宅基地

文章浏览阅读616次。一.jquery简介 jQuery是一个快速的,简洁的javaScript库,使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互 jQuery 的功能概括1、html 的元素选取2、html的元素操作3、html dom遍历和修改4、js特效和动画效果5、css操作6、html事件操作7、ajax_简介java中jquery技术

Ant Design Table换滚动条的样式_ant design ::-webkit-scrollbar-corner-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。我修改的是表格的固定列滚动而产生的滚动条引用Table的组件的css文件中加入下面的样式:.ant-table-body{ &amp;amp;::-webkit-scrollbar { height: 5px; } &amp;amp;::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box..._ant design ::-webkit-scrollbar-corner

javaWeb毕设分享 健身俱乐部会员管理系统【源码+论文】-程序员宅基地

文章浏览阅读269次。基于JSP的健身俱乐部会员管理系统项目分享:见文末!

论文开题报告怎么写?_开题报告研究难点-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏15次。同学们,是不是又到了一年一度写开题报告的时候呀?是不是还在为不知道论文的开题报告怎么写而苦恼?Take it easy!我带着倾尽我所有开题报告写作经验总结出来的最强保姆级开题报告解说来啦,一定让你脱胎换骨,顺利拿下开题报告这个高塔,你确定还不赶快点赞收藏学起来吗?_开题报告研究难点

原生JS 与 VUE获取父级、子级、兄弟节点的方法 及一些DOM对象的获取_获取子节点的路径 vue-程序员宅基地

文章浏览阅读6k次,点赞4次,收藏17次。原生先获取对象var a = document.getElementById("dom");vue先添加ref <div class="" ref="divBox">获取对象let a = this.$refs.divBox获取父、子、兄弟节点方法var b = a.childNodes; 获取a的全部子节点 var c = a.parentNode; 获取a的父节点var d = a.nextSbiling; 获取a的下一个兄弟节点 var e = a.previ_获取子节点的路径 vue

推荐文章

热门文章

相关标签