多线程

2018-05-03 14:27 更新

笔者能力有限,总结有误的地方,请读者协作更正。

1.什么是线程?

线程是操作系统中运算调度的最小单位,包含在进程中; 使用多线程在处理密集任务的时候可以提速。Java语言对多线程提供了很好的支持。

2.线程和进程的区别?

一个进程可以有很多线程,每条线程执行不同的任务。 不同进程有不同的内存空间,所有的线程共享一块内存空间。 每个线程都有单独的栈内存用来存储本地数据。

3 .线程的实现方式?

继承Thread类,实现Runnable接口;

Java继承的单根性,实现Runnable接口,重写run()方法实现线程。

4.Start和Run的区别?

Start启动新创建的线程,start内部调用run方法;

直接调用run方法,只会在原来的线程中调用,没有新的线程启动,start方法会启动新线程。

5. Runable和Callable有什么不同?

Runnable从jdk1.0就开始有的,Callable是jdk1.5增加的; Callable的call()方法可以有返回值和抛出异常,Runnable的run()方法没有这些功能; Callable还可以返回装载有计算结果的Future对象。

6. Java的内存模型?

Java的内存模型规定和指引了java程序在不同的内存架构,CPU和操作系统之间有确定性的行为; 它们在多线程的情况下尤其重要,内存模型为多线程之间的可见性提供了保证;

内存模型中有一块共享的内存空间——主内存,持有所有线程的共享变量,各个线程的的本地内存持有的仅是共享变量的副本;

当线程A发生变化的时候,将副本信息刷新到主内存中;线程B在主内存中读取线程A改变的信息。

7. volatile变量是什么?

在并发编程中缺少同步的情况下,多线程对成员变量的操作是透明的,其它线程可见; vlatile可以保证下一个读取操作会在前一个写操作之后发生,只有成员变量才能使用它。

8. 什么是线程安全?Vector是一个线程安全类么?

多线程情况下,同时执行一段代码,运行结果和单线程保持一致,就是线程安全;

Vector是用同步方法来实现线程安全的;ArrayList不是线程安全的;

9. Java中的竞态条件?例子

多线程对一些资源的竞争,首先要执行的程序竞争失败重新排队,导致整个流程没有按照预期的顺序处理,出现一些不确定的,很难发现的bug,这种情况是竞态条件; 例如:无序处理

10. Java中如何停止一个线程?

没有停止线程的API; JDK1.0提供,stop(),suspend(),resume()等控制线程的方法,已经被被弃用,太暴力; 当run()或者call()方法执行完之后线程会自动结束; 手动结束,可以调用interrupt()来中断线程,有一个中断标志。

11. 一个线程发生异常时会怎样?

没有捕获线程会停止执行,抛异常UncaughtExceptionHandler; JVM内部提供了Thread.getUncaughtExceptionHandler()来查询线程是否设置异常处理。

12. 如何实现两个线程之间共享数据?

可以通过共享对象来实现;

13.Notify和NotifyAll的区别?

Notify()唤醒单个线程; notifyAll()唤醒所有的线程,让他们争夺锁。

14. 为什么wait,notify、notifyall这些方法不在thread类里面?

这些方法防放在Object类里面; 因为java提供的锁是对象级的锁,而不是线程级的锁,每个对象都有锁,通过线程获得; 定义在Thread里面,不符合对象锁的设计。

15. 什么是ThreadLocal变量?

本地线程变量; 让每一个线程都有ThredLocal,竞态条件就被消除;

对于频繁创建对象的线程,使用它可以减少对象的创建个数,在线程本地内存中持有变量副本,不用每次都创建;

例如:使用ThreadLocal可以让SimpleDateFormat变成线程安全的;

16. Interrupted和isInterrupted方法的区别?

前者会将中断状态清除,后者不会; Java多线程中的中断机制是用内部标识来实现的,调用interrupt来中断一个线程会设置一个中断标志true,查询中断状态的时候,标志会被清除; 后者用来查询中断状态不会改变中断状态标志; 前者是静态的,后者是非静态的;

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

强制要求的,不这样做会抛异常IllegalMonitorStateException; 避免二者之间产生竞态条件;

18. Java中的同步集合与并发集合的区别?

同步集合与并发集合都为对线程提供了合适的线程安全的集合,并发集合扩展性更高;

Java5之前,只有同步集合,且在多线程并发的时候会导致争抢,阻碍看程序的扩展性;

Java5之后,出现并发集合,例如ConcurrentHashMap,不仅提供线程安全,还用锁分离和内部分区等,扩展性更好。

19. Java中堆和栈有什么不同?

栈是一块和线程紧密相关的内存区域,每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个栈中存储的变量对其它线程不可见;

堆是所有线程共享的一片公共内存区域,对象都在堆中创建; 为了提升效率,线程会从堆中弄一个缓存到自己的栈;

在多线程情况下,从公共内存中读取变量存在线程不安全问题,使用volatile变量可以保证线程安全。

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

创建若干数量的线程来等待响应处理,就叫线程池,线程池里面的线程叫工作线程; Java API提供了Execution框架可以创建不同的线程池;

Why? 创建线程需要花费昂贵的资源和时间,任务来了,在创建的话,响应时间就会变长,影响效率;

可以创建单线程池,每次处理一个任务;

可以创建固定数量的线程池,或者可扩展的线程池来处理 多任务;

比喻:线程池比喻 公交场

21. 如何解决生产者消费者问题?

一个线程生产任务,提供给其它线程进行消费 ,这就是属于生产者消费者模型;

生产者消费者问题,可以通过线程之间的通讯来解决,java API提供了wait和notify方法来解决这个问题; 更好的方法是Semaphore或者BlockingQueue来实现生产者消费者模型。

22. 如何避免死锁?

死锁是两个或两个以上的进程在执行的时候,争夺资源造成相互等待,程序卡死的一种现象;

死锁的发生存在下面四个条件:

互斥条件,一个资源每次只能被一个进程调用;

请求与保持条件,一个进程获得资源阻塞时,对已经获得的资源保持不放;

不剥夺条件,进程已经获得资源,在未使用完成之前,不强行剥夺;

循环等待条件,进程之间头尾相接等待资源释放;

避免死锁就是阻止循环等待条件,将系统中的所有资源设置标志位,排序,规定所有的进程在申请资源的时候按顺序执行(升序或降序);

23. Java中活锁和死锁的区别?

活锁,就是进程的状态可以改变,但是不能够执行; 例如,走廊里两个人相遇,一个让一个,一直让不开的现象。

死锁,就是进程的状态不能改变,也不能够执行; 例如,走廊里两个人相遇,堵在那儿不动的现象。

24. 怎样检查一个线程是否拥有锁?

Java.lang.Thread中有一个方法holdsLock(),返回true,当前线程持有锁;

25. Java中synchronized和RentrantLock有什么不同?

它们都是锁;

使用synchronized关键字作为锁来实现互斥,它可以锁方法,锁语句块,锁对象,但是不能够扩展锁之外的方法或者边界,尝试获取锁时候中途不能取消等;

Java5之后的lock接口提供了更为复杂的控制来解决并发问题; RentrantLock类实现了Lock,它拥有synchronized相同的并发性和内存语义且扩展性更好。

26. 有3个线程,怎样保证他们按照顺序执行?

有很多种方法; 可以使用join()方法在一个线程中启动另一个线程,

比如:A,B,C三个线程;将A join到b中,b join到c中,先启动C线程,按照c-b-a的顺序执行;

27. Thread类中的yield方法有什么作用?

可以暂停当前正在执行的线程对象,让优先级高的先执行;

它是一个静态方法,保证当前线程放弃CPU占用,而不保证优先级高的就一定执行,有可能线程刚暂停又立马恢复;

28. Java中的ConcurrentHashMap的并发度是什么?

ConcurrentHashMap把实际的map划分为若干部分来实现它的可扩展性和线程安全;

这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个构造参数,默认值是16,这样能在多线程情况下避免争用。

29. 如果你提交任务时候,线程池已经满,会发生什么?

会抛异常RejectedExecutionException;因为在非扩展线程池的情况下该线程任务不能够被调度。 **

  1. Java中线程池中的submit和execute方法有什么区别?**

两个方法都可以向线程池提交任务;

execute方法的返回值类型是void,定义在Execotor接口中;

Submit方法返回持有计算结果的future对象,它定义在ExecutorService接口中,它扩展了Exector接口;

其它的线程池类ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法;

31. 什么是阻塞式方法?

指程序会等待该方法完成,期间不会做其它的事情; ServerSocket类的accept方法就是阻塞式方法,会一直等待客户端连接;

阻塞指的是线程在调用结果返回之前,当前线程会被挂起,直到得到结果之后才会返回;

32. Java中的ReadWriteLock是什么?

读写锁,用来提升并发程序性能; Java5 新增的接口,一个读写锁维护一对关联的锁,一个用于读操作,一个用于写操作;

读锁是共享的,写锁是独占的。

33. 多线程中的忙循环是什么?

忙循环就是开发者用空循环让一个线程等待,一直持有CPU的控制;

不像wait(),sleep(),yield()等方法,放弃了CPU的控制;

好处是保留CPU缓存,减少线程等待,避免重建缓存。

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

线程会释放锁;

35. 单例模式的双检锁是什么 ?

它是用来创建线程安全的,写单例模式的老方法;

当单例实例第一次被创建时候它试图用单个锁进行性能优化,但是由于太过复杂几乎没人用。

36. 如何在java中创建线程安全的singleton?

双检索实现单例;

也可以通过JVM的类加载和静态变量初始化特征来创建单例;

或者利用枚举实现;

以上三种都是线程安全的可用的; **

  1. 写出3条你遵循的多线程最佳实践?**

1)给线程起一个有意义的名字 方便找bug或追踪线程执行;

2)避免锁定和缩小同步范围 锁花费的代价高昂,且上下文切换更耗费时间和空间,最低限度的使用同步锁,缩小临界区,有利于提升性能。

3)多用同步类,少用wait和notify CountDownLatch, Semaphore, CyclicBarrier 和 Exchanger 等这些同步类简化了编码操作; 而wait和notify很难实现相对复杂控制流控制; 使用高级的同步工具有利于优化线程;

4)多用并发集合少用同步集合 并发集合比同步集合扩展性好

38. 如何强制启动一个线程?

线程是被线程 调度器控制的,java中没有提供响应的API。

39. Java多线程中调用wait和sleep的方法有什么不同?

都可以让线程进入等待状态; wait方法用于线程间通信,如果等待条件为真且其它线程被唤醒是它会释放锁;

sleep方法仅仅是释放CPU的资源,让当前线程停止执行,不会释放锁;

- 其它

1.CyclicBarrier 和 CountDownLatch有什么不同?

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

2.什么是FutureTask?

在java并发编程中,FutrueTask表示一个可以取消的异步运算;

它有启动运算,取消运算,查询运算,取回运算等方法,只有单运算完成才能取回结果,运算未完成get将会被阻塞。

异步运算也是调用Runnable接口,可以交给Executor来执行。

3.为什么应该在循环中检查等待条件?

处在等待状态的线程可能会收到错误报警和伪唤醒,不在循环中检查等待,程序就会在没有满足条件的情况下退出;

当一个线程被notify时候,并不认为它原来的状态仍然有效,因为这段时间它有可能改变。

4.如何在java中获取线程堆栈?

JVM会把所有线程的状态存到日志文件,或者输出到控制台;

Windows中Ctrl+Break组合键获取; Linux下用kill -3 命令获取; 业可以用jps这个工具找到id;

5.JVM中的那个参数是用来控制线程的栈堆大小的?

-Xss用来控制线程栈堆大小;

6.Java中的semaphore是什么?

是一种新的同步类,是一个计数信号;

信号量维护了一个许可集合,未经许可的线程请求会被阻塞,获得许可请求才可以进入排队状态;

Semaphore只对可用许可的信号进行计数;

信号量常用在多线程代码种,比如数据库连接池等

7.Swing是线程安全的么? 为什么?

不是线程安全的;

因为swing的提供的组件不能再多线程中进行修改,所有对GUI组件的更新都需要在AWT线程中完成;

而swin提供了同步和异步两种回调方法来进行更新;

8.Java中的invokeAndWait和invokeLater方法有什么区别?

作用都是从当前线程更新GUI组件; 前者同步更新GUI组件,比如一个进度条,一旦更新了,进度条就要做出相应改变;

后者请求派线程更新组件,比如一个进度条,一旦更新,并没有更新,需要等待派发线程完成更新,才最终更新。

9.Swing API中的哪些方法是线程安全的 ?

Swing不是线程安全的,它的一些方法是线程安全的;

比如:repaint(),revalidata(),JTextComponent的setText()方法和JTextArea的insert()方法和append()方法等。

10.Java中volatile变量和atomic变量有什么不同?

Java中的volatile变量可以确保先行关系,写操作会发生在后续的读操作之前,但是并不能保证原子性;

例如用volatile修饰count变量,那么count++操作就不是原子性的; AtomicInteger类提供的atomic方法可以让这种操作具有原子性;

11.Java中的fork join框架是什么 ?

Fork join框架是JDK7出现的一款工具,java开发人员可以通过它,充分利用现代服务器上的多出来器;

可以将所有可用的处理能力调用起来提升程序性能;

它使用了工作窃取算法,可以完成更多任务的工作线程,可以从其它线程中窃取任务来执行。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号