多线程经典面试题及答案

java实现线程有哪几种方式

1.继承Thread类实现多线程
2.实现Runnable接口方式实现多线程
3.使用线程池:如ExecutorService,Callable,Future
第一种和第二种方式相比:java类只能允许继承一个父类,可以实现多个接口;其次,在第一种方式中用this可以获取当前线程,第二种方式获取当前线程只能通过Thread.currentThread()
第三种:线程的创建和释放,需要占用不小的内存和资源。如果每次需要使用线程时,都new 一个Thread的话,难免会造成资源的浪费,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪, ExecutorService是Java提供的线程池

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,

corePoolSize:核心线程数
maximumPoolSize:最大线程数
poolSize:线程池中当前线程的数量
那么poolSize、corePoolSize、maximumPoolSize三者的关系是如何的呢?
当新提交一个任务时:
(1)如果poolSize (2)如果poolSize=corePoolSize,新任务会被放入阻塞队列等待。
(3)如果阻塞队列的容量达到上限,且这时poolSize (4)如果阻塞队列满了,且poolSize=maximumPoolSize,那么线程池已经达到极限,会根据饱和策略RejectedExecutionHandler拒绝新的任务
ExecutorService分为以下几种线程池:可缓存线程池newCachedThreadPool(),其中创建的都是非核心线程,;单线程newSingleThreadExecutor();
固定线程池newFixedThreadPool(3);定时线程池

线程同步有哪几种方法

Synchronized,Lock锁,分布式锁
Synchronized,Lock锁的区别:
1.Synchronized是java内置关键字,Lock是java 类 Lock lock = new ReentrantLock()
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取锁lock.tryLock()
3.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平
4.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题
5.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
6.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了//lock.tryLock(3000, TimeUnit.MILLISECONDS) //尝试获取锁 获取不到锁,就等3秒,如果3秒后还是获取不到就返回false

synchronized与volatile区别

同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。volatile关键字用于声明简单类型变量,如int、float、boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制。并不是只要简单类型变量使用volatile修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如n=n+1、n++等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。

java中notify和notifyAll的区别

notify方法不能唤醒某个具体的线程,而notifyAll唤醒所有的线程并允许他们争夺锁,确保至少有一个线程能继续运行

为什么wait/notify/notifyAll这些方法不在thread类里面

一个明显的原因就是java提供的锁是对象级而不是线程级。每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中wait方法才有意义

什么是死锁

死锁是两个线程相互等待对方释放对象锁

启动线程方法start()和run()有什么区别

只有调用了start方法,才会表现多线程的特性,不同线程的run方法里面的带脉交替执行。如果只是调用了run方法,那么代码还是同步执行,必须等待一个线程的run方法里面的代码全部执行完,才会执行其自己的run方法里面的代码

多线程通信

wait/notify

java中用到了什么线程调度算法

抢占式。一个线程的cpu用完后,操作系统会根据线程优先级,线程饥饿情况等情况分配某个线程

synchronized有哪几种用法

锁类,锁方法,锁代码块

活锁,饥饿,无锁,死锁

死锁:多个线程互相占用对方资源的锁,又相互等待对方释放锁,若无外力干涉,这些线程则一直处于阻塞你的假死状态,形成死锁
活锁:指拿到资源却又相互释放不执行,这个资源在多个线程之间跳动又得不到执行
饥饿:指优先级高的线程一直占着优先级低的资源,导致优先级低的线程无法得到执行,处于长久等待中

你可能感兴趣的:(多线程经典面试题及答案)