Java并发之常见问题

2021/7/7 11:08:54

本文主要是介绍Java并发之常见问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

这里写目录标题

  • 1 Java中守护线程跟本地线程有什么区别?
  • 2 线程和进程的区别?
  • 3 什么是多线程的上下文切换
  • 4 什么是死锁?如何防止死锁?
  • 5 Java中用到的线程调度算法?
  • 6 为什么使用Executor框架?
  • 7 Executor和Executors的区别?
  • 8 原子操作类?
  • 9 Lock接口是什么?对比同步有什么优势?
  • 10 什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?
  • 11 什么是Callable和Future?
  • 11 什么是FutureTask?使用ExecutorService启动任务。
  • 12 CycliBarriar和CountdownLatch有什么区别?
  • 13 join方法可以使得一个线程在另一个线程执行完之后再去执行。
  • 14 lock 中的api

1 Java中守护线程跟本地线程有什么区别?

任何线程都可以设置为守护线程和用户线程,通过Thread.setDaemon(true)为守护线程,false为用户线程。但是注意得是:这个操作必须要在Thread.start()方法之前。
他俩得区别就是:当虚拟机中只剩垃圾守护线程得时候,jvm就会离开。守护线程是为用户线程服务的。用户线程是由程序创建的。

2 线程和进程的区别?

共享资源: 线程之间共享同一个进程下的地址空间以及资源,而进程之间为单独的地址空间。且进程之间的资源是相互独立的。

执行: 线程不能单独执行,必须依赖于进程。进程可以单独执行。
并发:都支持并发。

切换:进程之间进行上下文切换的时候,耗费的资源大。当涉及到频繁的切换时,使用线程要好一点.

3 什么是多线程的上下文切换

cpu执行程序是按cpu时间片来分配调度时间的,一个进程中包含了多个线程,每个时间片上最多只能运行一个线程,操作系统通过调度cpu时间片,让多个线程并发的执行,外界看起来好像多个线程是同时执行的。在每个cpu之间涉及到的切换,也就是线程之间的切换,即为上下文切换。为了让线程都有执行的机会,必须调度。
java中上下文切换的时候主要使用程序计数器来保存线程执行到哪一步,以便切换回来的时候可以继续执行,而不出错。

4 什么是死锁?如何防止死锁?

死锁就是互相占有对方的资源不放手,死锁造成的原因有四种:

  • 互斥条件:同一个资源在同一时刻只能被一个线程所持有。
  • 请求于保持条件:当占有锁的线程去请求其他资源的时候,对已经获取的资源不放手。
  • 不被剥夺条件:获取资源的线程,只要不主动释放, 就不会被剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

防止死锁就破坏后三个条件。
破坏请求与保持条件: 一次性请求多个资源。
破坏循环等待:获取锁和释放锁按顺序进行。
破坏不被剥夺条件:如果请求其他资源请求不到,可以主动释放。

5 Java中用到的线程调度算法?

计算机通常只有一个CPU,在任意时刻只能执行一条机器指令,每个线程只有获得cpu的使用权才能执行指令,所谓的多线程的并发与逆行其实是指从宏观上看,各个线程轮流获得cpu的使用权,分别执行各自的任务。在运行池中,回有多个处于就绪状态的线程在等待CPU,Java虚拟机的一项任务就是负责线程的调度。
有两种调度模型: 分时调度模型和抢占式调度模型
分时调度模型是指让所有的线程轮流获得cpu的使用权,并且平均分配每个线程占用的cpu的时间片这个也比较好理解。
Java虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。处于运行状态的线程一直运行,不得不放弃CPU。

6 为什么使用Executor框架?

  • 每次执行任务都new Thread()会比较耗费系统性能,创建一个线程是比较耗时耗资源的。
  • new的线程缺乏管理,线程之间的上下文切换很野。可以无限制的创建,可能会导致系统的瘫痪。
  • 使用Thread()不利于扩展

7 Executor和Executors的区别?

  • Executor是用来执行线程任务的。
  • Executors是用来创建不同的线程池的,以便满足不同的需求。

8 原子操作类?

AtomicInteger、atomicLong、Atomicboolean、AtomicReference
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater、AtomicLongFieldUpdater
解决ABA问题的原子类:
AtomicMarkableReference:通过引入一个boolean来反映中间有没有变过。
AtomicStampedReference:通过引入一个int来累加来反应中间有没有变过。

9 Lock接口是什么?对比同步有什么优势?

Lock接口比同步方法和同比代码块更具有扩展性。
Lock提供了无条件的、可轮询的(tryLock)、定时的(trylock带参数)、可中断的、可多田间队列的所操作。Lock的实现类基本都支持公平锁和非公平锁。当然大部分情况下,非公平锁是高效的选择。

10 什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?

阻塞队列是一个支持两个附加操作的队列。
① 在队列为空时,获取元素的线程会等待阻塞队列非空。
⑥ 当队列满时,存储元素的线程会等待队列可用。
LinkedBlockingDeque 链表实现的双向阻塞队列
Queue是单向,Dequeue是双向。

11 什么是Callable和Future?

Callable是创建线程的一个方式,只不过callable带有异常以及返回值。
这个返回值可以被Future拿到。
Futur接口表示异步任务,是还没有完成的任务给出的未来结果。Callable用来产生结果,Future接受结果。

11 什么是FutureTask?使用ExecutorService启动任务。

FutureTask表示一个可以取消的异步任务。可以交给Executors执行。

12 CycliBarriar和CountdownLatch有什么区别?

CyclicBarrier可以重复使用,而CountdownLatch不能重复使用
java的concurrent包里面的CoutDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去减这个计数器里面的值。你可以向CountDownLatch对象设置一个数字作为计数值。然后又两个方法 await() 调用方法一直阻塞,知道计数为0、countdown()方法会将计数值减1.

13 join方法可以使得一个线程在另一个线程执行完之后再去执行。

public class thread1 {
    public static void main(String[] args) throws InterruptedException {
        tt t1 = new tt();
        tt t2= new tt();
        tt t3= new tt();
        t1.start();
        t1.join();
        t2.start();
        t2.join();
        t3.start();
        t3.join();

    }
    static class tt extends  Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " :" + i);
            }
        }
    }
}

14 lock 中的api

lock: lock是正常的获取锁,获取不到锁就等待
trylock:与lock一样 获取成功返回true,获取失败返回false
trylock(参数1,参数2):获取锁获取失败会等待指定的时间
interupt:线程获取不到锁,进入等待状态,可以调用线程的interupt中断线程的等待。


这篇关于Java并发之常见问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程