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中饥饿和活锁?
  • 饥饿:一个线程一直占用资源导致其他线程处于等待状态,类似死锁,但是不同于死锁的是在此线程结束后会释放资源
  • 活锁:状态在一直改变,但不会执行。如:程序中存在一个资源,多个线程都将执行机会给其他线程,导致资源来回在多个线程中,但又得不到执行
说说线程同步的方法?
  • wait():Object类中的方法,使一个线程处于等待状态,会将对象锁释放
  • sleep():Thread类中的方法,使一个线程在指定时间内处于休眠状态,休眠时间结束就会正常执行,不会释放对象锁
  • notify():Object类中的方法,随机唤醒一个线程,由JVM控制
  • notifyAll():Object类中的方法,唤醒所有线程
线程的基本概念、线程的基本状态以及状态之间的关系?
  • 在一个进程中,执行进程代码的一个操作单元,一个进程至少有一个线程,即进程本身
  • 线程的基本状态:
    • 新建状态:使用new创建一个线程对象,与其他新建对象一样都只分配了内存
    • 等待状态:在new创建对象之后使用start()方法之前
    • 就绪状态:线程对象调用start()方法,JVM将线程放入可运行池中,等待分配CPU使用权
    • 运行状态:此状态的线程持有CPU使用权,执行程序中的代码
    • 阻塞状态:线程因为某些原因导致线程阻塞,停止执行。阻塞状态的线程JVM不会分配CPU的使用权,直到重新处于就绪状态,线程才有机会被分配到CPU的使用权
      • 阻塞状态分为3种:
        等待阻塞:线程对象调用wait()方法,线程释放对象锁,JVM将线程放入等待池中
        同步阻塞:线程对象需要得到资源锁,此资源锁又被其他线程所占用时,JVM会将线程放入锁池中,等待资源锁被释放并竞争资源锁
        其他阻塞:线程对象调用sleep()方法,或发送IO请求时,JVM会将线程置为阻塞状态,在sleep()休眠时间结束,或IO请求处理完毕之后,线程会重新进入就绪状态
    • 死亡状态:run方法被执行完,或遇到未捕获的异常线程终止执行,此时线程就处于死亡状态,结束线程的生命周期
  • 状态之间的关系:
创建线程有哪几种方法?
  • 继承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 a=0; a++; 
      • a++ 分为三个步骤执行:
        • 内存到寄存器
        • 寄存器自增
        • 写入内存
      • 对于变量a而言具有修改可见性,但a++三个步骤都能够被分离开,不符合原子性的操作,所以存在线程安全问题
synchronize和volatile的区别?
  • volatile是变量的修饰符,synchronize是修饰类、方法和代码块的
  • volatile只能保证修改的可见性,不能保证原子性,synchronize既能保证修改的可见性,又能保证原子性
  • volatile不会造成线程阻塞,synchronize可能会造成线程阻塞
  • volatile修饰的变量不会被编译器优化,synchronize标记的会被编译器优化
Java中synchronize和ReentrantLock的区别? 
  • ReentrantLock使用比较灵活,但是需要手动释放锁
  • ReentrantLock必须手动加锁和释放锁,synchronize不需要手动加锁和释放锁
  • ReentrantLock只适用于代码块,synchronize可用于类、方法、代码块中
synchronize和Lock的区别?
  • synchronize是自动锁,Lock需要自己手动加锁和释放锁
  • synchronize使用比较简单,当发生异常时会自动释放锁,不会产生死锁,Lock使用不当,没有使用unLock()释放锁,则会产生死锁
  • Lock只能给代码块加锁,synchronize能给类、方法、代码块加锁
  • Lock可以知道是否获取了对象锁,而synchronize无法判断是否得到对象锁
  • 使用锁机制不同:
    • synchronize:使用了悲观锁机制,即独占锁机制,认为每个线程访问资源都会对同一资源进行修改,所以规定每次只能进入一个线程。在CPU转换线程阻塞时会导致上下文的切换,当有很多线程竞争锁时,CPU频繁的上下文切换就会导致效率将低
    • Lock:使用了乐观锁机制,认为进入的线程都不会对同一资源进行修改,如果产生冲突,就会进行重试
start()和run()方法的区别有哪些?
  • start()用于启动线程,run()执行线程运行时的代码,start()只能运行一次,run()能够被多次调用
为什么wait、notify和notifyAll这些方法不在Thread类中?
  • 因为wait、notify和notifyAll都是锁级别的操作,所以这些方法都在Object类中,锁属于对象
notify和notifyAll的区别?
  • notify:将随机唤醒一个线程,由JVM进行控制
  • notifyAll:将所有线程唤醒
  • 等待线程由等待池移到锁池中,之后通过锁的竞争来获取锁,获得则进入就绪状态等待分配CPU的使用权,否则就在锁定池中等待进行下一次锁的竞争,如此反复
为什么wait、notify和notifyAll方法要在同步块中调用?
  • 因为防止wait和notifyAll/notify产生竞态条件
    • 假设我们有这样一个场景,消费者线程需要生产者线程写入一次数据,生产者线程需要消费者线程读取一次数据。在不使用同步机制时,当生产者线程wait执行的同时消费者线程notify也执行,消费者线程notify在等待池中未找到生产者线程,那么此时的生产者线程wait会一直处于阻塞状态
ThreadLocal是什么?有哪些使用场景?
  • ThreadLocal为所有线程提供线程副本,每个线程都能够独立的修改自己的线程副本,并且不会影响其他线程的副本
  • 使用场景:
    数据库的连接
    session的管理
为什么stop()和suspend()都不推荐使用?
  • stop():不安全,它会释放线程的所有锁,如果线程对象处于不连贯状态的话,那么其他线程就有可能进行检查和修改它们,且主要问题很难检测出来
  • suspend():容易造成死锁,因为线程调用了suspend()方法不会释放锁,其他线程不能访问到这些资源,从而导致线程阻塞
线程池中submit()和execute()方法有什么区别?
  • execute():只能执行Runnable类型的任务
  • submit():Runnable类型和Callable类型的任务都能执行
atomic的原理是什么?
  • atomic主要是利用CAS(Compare And Swap 比较交换 是一种无锁机制)、volatile和native来保证原子操作,从而避免synchronize的高开销,执行效率大大提升

转载于:https://www.cnblogs.com/Fmir/p/11338351.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值