线程总结

线程:

面试题:https://blog.csdn.net/weixin_40205234/article/details/86645877

 

1.线程概念

2.创建线程方式

3.线程安全问题

    解决方法之一就是用加锁,synchronized和显式锁。(还有三个同步工具类)

 4.多种线程案例,例如DCL

5.wait ,   notify()

 6.消费生产(卖票问题)

 

多线程就是为了提高程序效率。

 

 

上下文切换

任务从保存到再加载的过程就是一次上下文切换。上下文切换对系统来说意味着消耗大量的 CPU 时间,所以减少上下文切换的方法有:让步式上下文切换抢占式上下文切换,

总之就是,减少锁的使用、使用CAS算法、减少线程使用、使用协程。

 

 

问题汇总:

1.有T1、T2、T3三个线程,如何保证T2在T1执行完后执行,T3在T2执行完后执行?

    用join语句,在t3开始前join t2,在t2开始前join t1。

    不过,这会破坏多线程的并发性,不建议这样做。

 

2.wait和sleep方法有什么不同?

  • wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
  • wait() 会释放锁,sleep() 不会。

3.notify和notifyAll方法有什么差别和联系?

都在synchronzied中执行,notify执行后会唤醒因调用wait方法而等待对象锁的其他线程,得到通知的线程就能继续得到对象锁从而继续执行下去

但notifyAll 执行后会去竞争对象锁,如果其中一个线程获得了对象锁,则会继续执行,在它退出synchronized代码释放锁后,其它的已经被唤醒的线程则会继续竞争,以此类推,直到所有被唤醒的线程都执行完毕

notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。

 

4.synchronized 和 ReentrantLock有什么不同?它们各自的适用场景是什么?

    synchronized可以作用在方法和代码块上,但无法锁住由多个方法组成的业务块,而ReentrantLock可以保证业务层面的并发

 

5.Java中CyclicBarrier 和 CountDownLatch有什么不同?

CyclicBarrier 和 CountDownLatch 都可以用来让一组线程等待其它线程。与 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。

 

6.什么是线程安全?

所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

 

7.一个线程运行时发生异常会怎样?

如果该异常被捕获或抛出,则程序继续运行。 
如果异常没有被捕获该线程将会停止执行

 

8.如何在两个线程间共享数据

每个线程执行的代码相同,可以使用同一个Runnable对象

每个线程执行的代码不同,用不同的Runnable对象

 

9.为什么wait, notify 和 notifyAll这些方法不在thread类里面?

由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。

 

10.Java中interrupted 和 isInterruptedd方法的区别?

interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会

 

11.为什么wait和notify方法要在同步块中调用?

因为Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。

 

12.volatile的作用:

使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效。Volatile 关键字的作用是变量在多个线程之间可见

volatile具有可见性、有序性,不具备原子性。

 

13. 什么是线程池? 为什么要使用它?

创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池。 共有四种创建方法。调用他们的 execute 方法即可。

线程池的好处:

降低资源消耗、提高响应速度、提高线程的可管理性

线程池原理剖析:

提交一个任务到线程池中,线程池的处理流程如下:

1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。

2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程

3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个

 

 

14.如何避免死锁?

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。

 

15. 怎么检测一个线程是否拥有锁?

在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。

 

16.如果你提交任务时,线程池队列已满。会时发会生什么?

事实上如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常。

 

17如果同步块内的线程抛出异常会发生什么?

无论你的同步块是正常还是异常退出的,里面的线程都会释放锁,所以对比锁接口我更喜欢同步块,因为它不用我花费精力去释放锁,该功能可以在finally block里释放锁实现。

 

18. Java多线程中调用wait() 和 sleep()方法有什么不同?

wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。

 

19.什么是多线程安全?

当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题.

 

20.什么是多线程死锁?

同步中嵌套同步,无法释放锁的资源。解决办法:同步中尽量不要嵌套。

 

21.如何停止线程?

使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。
使用 stop 方法强行终止线程(这个方法不推荐使用,因为 stop 和
suspend、resume 一样,也可能发生不可预料的结果)。
使用 interrupt 方法中断线程。 线程在阻塞状态

 

22.什么是守护线程

Java 中有两种线程,一种是用户线程,另一种是守护线程。
当进程不存在或主线程停止,守护线程也会被停止。
使用 setDaemon(true)方法设置为守护线程

 

23.join()方法作用

join 作用是让其他线程变为等待,只有当前线程执行完毕后,等待的线程
才会被释放。

 

24.说说 Java 内存模型

共享内存模型指的就是 Java 内存模型(简称 JMM),JMM 决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM 定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是 JMM 的一个抽象概念,并不真实存在。

 

25.什么是 AtomicInteger

AtomicInteger 原子类。

 

26.多线程间的通信怎么实现

1.共享变量

2.wait() 。notify()

 

posted @ 2019-02-25 16:22  StingLon  阅读(241)  评论(0)    收藏  举报