金三银四跳槽季(四)多线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dreamsunday/article/details/79964257

1、 wait和sleep的区别

sleep()方法是属于Thread类中的,而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。所以在调用sleep()方法的过程中,线程不会释放对象锁。
③调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

2、Volatile和Synchronized四个不同点:

① 粒度不同,前者针对变量 ,后者锁对象和类
syn阻塞,volatile线程不阻塞
syn保证三大特性,volatile不保证原子性
syn编译器优化,volatile不优化 volatile具备两种特性:

1.保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。
2.禁止指令重排序优化。

Volatile如何保证内存可见性:

1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

  • 同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。
  • 异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被>依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。
  • 阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。
  • 非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。
    非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。

3、线程池的作用:

在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程


  • 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  • 第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

  • 第三:提高线程的可管理性。

常用线程池:ExecutorService 是主要的实现类,其中常用的有 Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()

4、notify和notifyAll区别

他们的作用都是通知处于等待该对象的线程。

  • notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。

  • notify是通知其中一个线程,不会通知所有的线程

2、实现线程有哪几种方式?

有三种方式可以用来创建线程:

  • 继承Thread类
  • 实现Runnable接口
  • 应用程序可以使用Executor框架来创建线程池

实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。

3、线程有哪几种状态?它们之间如何流转的?

4、线程中的start()和run()方法有什么区别?

只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。

5、怎么终止一个线程?如何优雅地终止线程?

①使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){……}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。

②使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。

6、ThreadLocal在多线程中扮演什么角色?

简单说ThreadLocal就是一种以空间换时间的做法,在每个Thread里面维护了一个以开地址法实现的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了

7、用过并发包的哪些类

SemaphoreCyclicBarrieCountDownLatchCompletionService

8、多线程同步有哪几种方法?

9、什么是死锁?如何避免死锁?

两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中。
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。

10、多线程之间如何进行通信?

通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAllawait/signal/signalAll进行唤起和等待,比方说阻塞队列BlockingQueue就是为线程之间共享数据而设计的

11、线程怎样返回结果?如何获取?

12、说说violatile关键字有什么用,和Synchronized有什么区别?

使多线程中的变量可见;
volatile不需要加锁,比synchronized更轻量级,不会阻塞线程

从内存可见性角度讲,volatile读相当于加锁,volatile写相当于解锁

synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性

13、假如新建T1、T2、T3三个线程,如何保证它们按顺序执行?

这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。

14、怎么控制同一时间只有3个线程运行?

Semaphore

15、为什么要使用线程池?

避免频繁地创建和销毁线程,达到线程对象的重用。另外,使用线程池还可以根据项目灵活地控制并发的数目。

16、说一说常用的几种线程池并讲讲其中的工作原理。

newSingleThreadExecutor

newFixedThreadPool

newCachedThreadPool

newScheduledThreadPool

newWorkStealingPool

17、线程池启动线程submit()和execute()有什么不同?

execute适用于不需要关注返回值的场景,只需要将线程丢到线程池中去执行就可以了

submit方法适用于需要关注返回值的场景

18、说说多线程并发控制中的倒计时器、循环栅栏是什么,有什么应用场景?

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时CyclicBarrier很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

19、什么是活锁、饥饿、无锁、死锁?

20、什么是原子性、可见性、有序性?

原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

可见性:是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

有序性:即程序执行的顺序按照代码的先后顺序执行。

21、什么是守护线程?有什么用?

守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,连jvm都停止运行了,守护线程当然也就停止执行了。

再换一种说法,如果有用户自定义线程存在的话,jvm就不会退出——此时,守护线程也不能退出,也就是它还要运行,干嘛呢,就是为了执行垃圾回收的任务啊。

22、怎么中断一个线程?如何保证中断业务不影响?

23、yield()方法有什么用?

24、什么是重入锁,和Synchronized锁有什么区别?

如果锁具备可重入性,则称作为可重入锁。像synchronizedReentrantLock都是可重入锁
锁的实现

synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的,有什么区别,说白了就类似于操作系统来控制实现和用户自己敲代码实现的区别。前者的实现是比较难见到的,后者有直接的源码可供阅读。

synchronized在JVM层面实现,不但可以通过一些监控工具监控锁定,而且在代码执行出现异常,JVM自动释放锁定;
Lock是通过代码实现,为了保证锁定一定会被释放,一般会将unLock()放到flyinal{}中。

性能的区别

在资源竞争不激烈的情况下,synchronized的性能要优于ReentrantLock,但在资源竞争很激烈的情况下,synchronized的性能会下降几十倍,但是ReentrantLock的性能能维持常态。

Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

功能的区别

便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。

锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized

25、Synchronized有哪几种用法?

synchronized关键字来声明synchronized方法
synchronized代码块

26、Fork/Join框架是干什么的?

27、如何给线程传递参数?

28、说说线程安全的和不安全的集合。

29、什么是CAS算法?在多线程中有哪些应用。

CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换

CAS机制当中使用了3个基本操作数:内存地址V旧的预期值A要修改的新值B

更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。例如AtomicBooleanAtomicIntegerAtomicLong。它们分别用于BooleanIntegerLong类型的原子性操作。

30、你遇到过哪些多线程的问题?都是如何解决的

31、volatile如何保证可见性

使用volatile修饰时,可以理解成所有的操作都放到了主存中,,多个线程共享数据时,可以保证内存中的数据可见,一个线程修改了数据,会立即更新到主存,下一个线程使用时一定是最新的数据,这便是可见性

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页