加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Java线程

发布时间:2020-12-15 08:23:31 所属栏目:Java 来源:网络整理
导读:并行和并发的区别? 并行:多个处理器同时处理多个任务 并发:一个处理器处理多个任务,按照细分时间交替执行,在逻辑上是同时执行的 线程同步和线程通信的理解? 线程同步:指的是当一段代码,正在被一个线程执行时,不能存在其他线程也在执行。Java给我们提
  1. 并行和并发的区别?
    • 并行:多个处理器同时处理多个任务
    • 并发:一个处理器处理多个任务,按照细分时间交替执行,在逻辑上是同时执行的
  2. 线程同步和线程通信的理解?
  • 线程同步:指的是当一段代码,正在被一个线程执行时,不能存在其他线程也在执行。Java给我们提供了两种方式:
    • synchronize(同步监视器):
      • 特点:不能修饰构造器与成员变量,能修饰类、方法和代码块;自动锁
      • 以下情况会导致synchronize释放锁:
        • 当代码块或方法执行完毕时
        • 线程在代码块或方法中遇到return、break时
        • 线程在代码块或方法中遇到未处理的异常时
        • 线程在代码块或方法中遇到锁对象使用wait()方法时
    • 同步锁(Lock):通过显示定义同步锁对象实现同步
      • 特点:只能修饰代码块;需要自己手动的加锁和释放锁
      • ReentrantLock是Lock的实现类,具有可重入性。可重入性指的是,线程可以在被加锁的ReentrantLock的锁上再次加锁
      • ReentrantLock对象维持一个计数器追踪lock()方法的嵌套调用,所以一个被锁保护的代码可以调用另一个被锁保护的代码
  • 线程通信:线程之间的协调执行
      • 线程通信是基于synchronize机制和条件变量完成的。通过查询执行条件,判断是执行还是继续等待,继续等待就执行锁对象的wait()方法。继续执行,执行完毕后,改变条件变量,并且使用notify唤醒其他线程,如此循环
      • 例:一个银行账户,系统命令一直存钱和取钱
    ???????????????

  • 线程和进程的区别?
    • 在一个程序中,至少拥有一个进程,一个进程至少拥有一个线程
  • Java中的竞态条件是什么?如何解决?
    • 在一个程序中,多个线程访问同一资源,如果对资源访问顺序敏感(如:加减乘除),就称存在竞态条件
    • 竞态条件一般发生在代码的临界区,如:
    • 当两个线程同时执行add方法,分别是add(2)和add(3),正常情况得出的结果应该是5,但是如果两个线程在获取count的值时count都为0的话,结果也就不会是5
    • 解决方式:使用synchronize或者Lock显示锁
  • 线程运行时发生异常会怎么样?
    • 如果异常已经被捕获并且抛出,那么线程会继续执行
    • 如果异常没有被捕获那么线程会停止执行,并抛出Tread.UncaughExceptionHandler异常,此接口是处理导致线程停止执行的未捕获异常的内嵌接口
  • 说说synchronize的锁升级原理?
    • 在锁对象中设置thread Id值,在第一次使用时thread Id为空,JVM让其持有偏向锁,并且将thread Id设置为此线程的Id,当下一次进行访问时,会判断thread Id和此线程Id是否相同,相同则直接使用此对象;不同,则JVM就会将锁升级为轻量级锁,通过自旋循环一定次数获得锁,如果循环了一定次数没有获得锁,那么就会将锁升级为重量级锁来获得锁。此过程就是锁的升级
    • 锁的升级目的是为了降低所带来的性能消耗
  • 在Java程序中怎么保证多线程的运行安全?
    • 使用java.util.concurrent中的类
    • 使用自动锁synchronize
    • 使用手动锁Lock
  • Java中堆和栈有什么不同?
    • 栈:是与线程密切相关的内存区域。每个线程都拥有自己的栈内存,用于存储本地变量、方法参数以及栈调用等。每个线程在栈内存中存储的信息对于其他线程都是不可见的
    • 堆:是所有线程的共享内存区域。每个对象都是在堆内存中创建的,为了提高效率线程都会从堆中放一个缓存到栈中
  • 线程池是什么?为什么使用它?
    • 线程池的四大基本组成部分:
      • 线程池管理器(ThreadPool):主要负责创建线程池、销毁线程池以及创建新任务
      • 工作线程池(PoolWorker):线程池的线程,没有执行任务时处于等待状态,能够循环执行任务
      • 任务接口(Task):任务必须实现的接口,目的是使工作线程调度任务的执行,它主要是任务的入口、任务结束后的收尾操作以及获得任务的执行状态等
      • 任务队列(TaskQueue):存放未处理的任务队列,提供一个缓冲机制
    • 在线程需要被多次使用时,反复的创建和销毁线程,对于资源消耗是很大的,而线程池能够减少线程的创建和销毁,让线程能够多次被使用,我们也可以根据需要来控制创建线程的数量,这样我们就能减少内存的使用以及资源消耗
  • 什么是死锁?
    • 当A线程拥有独占锁a,尝试获取独占锁b时,同时B线程拥有独占锁b,尝试获取独占锁a时,此时就发生了锁的竞争,AB两个线程都拥有彼此需要的锁,这就是死锁
  • 如何避免死锁?
    • 尽量使用java.util.concurrent中的类代替自己手写锁
    • 尽量使用tryLock(long timeOut,TimeUnit unit)方法,设置超时时间,超时即可退出
    • 降低锁的粒度,避免多个功能使用同一个锁
    • 减少同步代码块的使用
  • Java中死锁和活锁的区别?
  • 说说线程同步的方法?
  • 线程的基本概念、线程的基本状态以及转态之间的关系?
  • 创建线程有哪几种方法?
    • 继承Thread类,执行run()方法
    • 实现Runnable接口
    • 实现Callable接口
  • Java中Runnable和Callable有什么不同?
    • Runnable:run()方法无返回值
    • Callable:call()方法有返回值
  • sheep()和wait()有什么区别?
    • sheep():来自Tread类,不会释放锁,消耗完指定时间会自动恢复
    • wait():来自Object类,会释放锁,需要使用notify/notifyAll进行唤醒,将等待池中的线程移到锁池中,然后进行锁的竞争
  • Java中的volatile变量是什么?
    • volatile修饰的变量不会执行加锁操作,所以不会导致线程的阻塞,volatile是比synchronize更轻量级的同步机制
    • 特点:
      • volatile能够保证线程修改的可见性【即:当一个线程对共享内存中的变量进行修改时,其他线程能够立即获得修改之后的值】,volatile能够将新值立即同步到主内存中,每次使用时也会立即在主内存中刷新
      • 提供了禁止指令重排序的优化,线程在使用volatile修饰的变量时,JVM会先执行一个操作,这个操作就是内存屏障【即:先于指令的操作必须先执行,后于指令的操作必须后执行】
      • 没有被volatile修饰的变量,线程在使用时会先将内存中的变量存入CPU缓存中;volatile修饰的变量,JVM保证每次读写都在内存中执行
    • 缺点:
      • volatile不能保证原子性
        例:volatile int i=0; a++;?
        ?  ? ? 对于变量a而言具有修改可见性,但a++操作就不符合原子性的操作,所以存在线程安全问题
  • synchronize和volatile的区别?
    • volatile是变量的修饰符,synchronize是修饰类、方法和代码块的
    • volatile只能保证修改的可见性,不能保证原子性,synchronize既能保证修改的可见性,又能保证原子性
    • volatile不会造成线程阻塞,synchronize可能会造成线程阻塞
    • volatile修饰的变量不会被编译器优化,synchronize标记的会被编译器优化
    • 使用锁的机制不一样
      • synchronize:使用悲观锁的机制,即独占锁机制,认为其他线程都会对资源进行修改,所以每次只允许一个线程进行读写。在CPU转换线程阻塞时会导致上下文的切换,当有很多线程竞争锁时,CPU频繁的上下文切换会导致效率很低
      • Lock:使用乐观锁的机制,认为其他线程都不会对资源进行修改,如果产生冲突,则会进行重试直到成功
  • Java中synchronize和ReentrantLock的区别?
    • ReentrantLock使用比较灵活,但是需要手动释放锁
    • ReentrantLock必须手动加锁和释放锁,synchronize不需要手动加锁和释放锁
    • ReentrantLock只适用于代码块,synchronize可用于类、方法、代码块中
  • synchronize和Lock的区别?
    • synchronize是自动锁,Lock需要自己手动加锁和释放锁
    • synchronize使用比较简单,当发生异常时会自动释放锁,不会产生死锁,Lock使用不当,没有使用unLock()释放锁,则会产生死锁
    • Lock只能给代码块加锁,synchronize能给类、方法、代码块加锁
    • Lock可以知道是否获取了对象锁,而synchronize无法判断是否得到对象锁
  • start()和run()方法的区别有哪些?
    • start()用于启动线程,run()执行线程运行时的代码,start()只能运行一次,run()能够被多次调用
  • 为什么wait、notify和notifyAll这些方法不在Thread类中?
    • 因为wait、notify和notifyAll都是锁级别的操作,所以这些方法都在Object类中,锁属于对象
  • notify和notifyAll的区别?
    • notify:将一个线程唤醒,当没有指定则随机唤醒一个线程,由JVM进行控制
    • notifyAll:将所有线程唤醒
    • 等待线程由等待池移到锁池中,之后通过锁的竞争来获取锁,获得就继续执行,没有获得则在锁定池中等待进行下一次锁的竞争,如此反复
  • 为什么wait、notify和notifyAll方法要在同步块中调用?
    • 因为防止wait和notifyAll/notify产生竞态条件
      • 假设我们有这样一个场景,消费者线程需要生产者线程写入一次数据,生产者线程需要消费者线程读取一次数据。在不使用同步机制时,当生产者线程wait执行的同时消费者线程notify也执行,消费者线程notify在等待池中未找到生产者线程,那么此时的生产者线程wait会一直处于阻塞状态
  • ThreadLocal是什么?有哪些使用场景?
    • ThreadLocal为所有线程提供线程副本,每个线程都能够独立的修改自己的线程副本,并且不会影响其他线程的副本
    • 使用场景:
      数据库的连接
      session的管理
  • 为什么stop()和suspend()都不推荐使用?
  • 线程池中submit()和execute()方法有什么区别?
    • execute():只能执行Runnable类型的任务
    • submit():Runnable类型和Callable类型的任务都能执行
  • atomic的原理是什么?
    • atomic主要是利用CAS(Compare And Swap)、volatile和native来保证原子操作,从而避免synchronize的高开销,执行效率大大提升
  • (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读