[关闭]
@yexiaoqi 2018-12-04T10:14:39.000000Z 字数 3160 阅读 884

线程

java面试总结


1. 多线程的好处?

答:多核CPU下资源利用率高,效率高

2. 线程概念

3. 开启线程的方式

  1. 继承Thread类,重写run方法。创建本类对象,调用start( )开启线程
  2. 实现Runable接口,重写run方法。创建Thread类对象,传递本类对象,调用start( )开启线程
  3. 实现Callable接口,重写call方法,需要依赖于线程池执行。

4. 线程的状态

5. 线程池

  1. jdk1.5 API中提供了ExecutorService(接口)表示线程池,实现类ThreadPoolExecutor。此类的某个构造方法有7个参数,分别是:
    • corePoolSize - 池中所保存的线程数,包括空闲线程数。
    • maximumPoolSize - 池中允许的最大线程数。
    • keepAliveTime - 单线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
    • unit - keepAliveTime参数的时间单位
    • workQueue - 执行前用于保持任务的队列。此队列仅保持由execute方法提交的Runnable 任务。
    • threadFactory - 执行程序创建新线程时使用的工厂。
    • handler - 由于超出线程范围和队列容量而使执行被阻断时所使用的处理程序。
  2. 使用工具类获取API提供的线程池:Executors
    • newCachedThreadPool():带缓存功能的线程池
    • newFixedThreadPool(int nThreads):可以指定固定个数的线程池
    • newScheduledThreadPool(int corePoolSize):支持定时和周期性执行任务的线程池。
    • newSingleThreadExecutor():只有一个线程的线程池,内部维护一个任务队列,依次执行
  3. 常见的线程工具类
    1. Semaphore:信号量,允许同一时间有指定个数的线程执行同一任务
    2. CountDownLatch:用来协调多个线程之间的同步。能够使一个线程在等待另外一些线程完成各自的工作之后,再继续执行,使用一个计数器实现。
    3. CyclicBarrier:它要做的事是让一组线程到达一个屏障(同步点)时被阻塞,知道最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续工作。

6.死锁

  1. 请写一段死锁的代码
  1. public class DeadLock {
  2. String resource1 = "资源1";
  3. String resource2 = "资源2";
  4. Thread t1 = new Thread("线程1"){
  5. public void run() {
  6. while (true){
  7. synchronized (resource1){
  8. try {
  9. Thread.sleep(500);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. synchronized (resource2){
  14. System.out.println("线程1拥有"+resource1+",需要"+resource2);
  15. }
  16. }
  17. }
  18. }
  19. };
  20. Thread t2 = new Thread("线程2"){
  21. public void run() {
  22. while (true){
  23. synchronized (resource2){
  24. try {
  25. Thread.sleep(500);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. synchronized (resource1){
  30. System.out.println("线程2拥有"+resource2+",需要"+resource1);
  31. }
  32. }
  33. }
  34. }
  35. };
  36. public static void main(String a[]){
  37. DeadLock test = new DeadLock();
  38. test.t1.start();
  39. test.t2.start();
  40. }
  41. }

线程常见面试题

  1. 死锁了如何解决?思路?

    • 按照顺序加锁
    • 尝试获取锁的时候加一个超时时间,如果超时,则回退并释放所有已获得的锁,然后等待一段随机的时间再试。
    • 死锁检测
  2. 使用Callable+FutureTask获取执行结果的例子

  1. public class Test {
  2. public static void main(String[] args) {
  3. //第一种方式
  4. ExecutorService executor = Executors.newCachedThreadPool();
  5. Task task = new Task();
  6. //用任务对象构造一个FutureTask对象
  7. FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
  8. //直接把FutureTask对象提交给线程池,让去执行
  9. executor.submit(futureTask);
  10. executor.shutdown();
  11. //第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread
  12. /*Task task = new Task();
  13. FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
  14. //通过FutureTask对象构造一个线程对象
  15. Thread thread = new Thread(futureTask);
  16. thread.start();*/
  17. try {
  18. Thread.sleep(1000);
  19. } catch (InterruptedException e1) {
  20. e1.printStackTrace();
  21. }
  22. System.out.println("主线程在执行任务");
  23. try {
  24. //执行完后,futureTask.get()获取线程执行结果
  25. System.out.println("task运行结果"+futureTask.get());
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. } catch (ExecutionException e) {
  29. e.printStackTrace();
  30. }
  31. System.out.println("所有任务执行完毕");
  32. }
  33. }
  34. class Task implements Callable<Integer>{
  35. @Override
  36. public Integer call() throws Exception {
  37. System.out.println("子线程在进行计算");
  38. Thread.sleep(3000);
  39. int sum = 0;
  40. for(int i=0;i<100;i++)
  41. sum += i;
  42. return sum;
  43. }
  44. }
  1. Future接口中定义的几个方法,简单介绍一下

boolean cancel(boolean mayInterruptInRunning) 取消一个任务,并返回取消结果。参数表示是否中断线程。
boolean isCancelled() 判断任务是否被取消
Boolean isDone() 判断当前任务是否执行完毕,包括正常执行完毕、执行异常或者任务取消。
V get() 获取任务执行结果,任务结束之前会阻塞。
V get(long timeout, TimeUnit unit) 在指定时间内尝试获取执行结果。若超时则抛出超时异常

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注