线程
线程
1、创建线程的方式及实现
答:A、继承Thread类创建线程。B、实现Runnable接口创建线程 C、使用Callable和Future创建线程
------------------------继承Thread类创建线程---------------------
通过继承Thread类来创建并启动多线程的一般步骤如下:
1】d定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。
2】创建Thread子类的实例,也就是创建了线程对象
3】启动线程,即调用线程的start()方法
代码实例
public class MyThread extends Thread{//继承Thread类
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
new MyThread().start();//创建并启动线程
}
}
------------------------实现Runnable接口创建线程---------------------
通过实现Runnable接口创建并启动线程一般步骤如下:
1】定义Runnable接口的实现类,一样要重写run()方法,这个run()方法和Thread中的run()方法一样是线程的执行体
2】创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象
3】第三部依然是通过调用线程对象的start()方法来启动线程
代码实例:
public class MyThread2 implements Runnable {//实现Runnable接口
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
//创建并启动线程
MyThread2 myThread=new MyThread2();
Thread thread=new Thread(myThread);
thread().start();
//或者 new Thread(new MyThread2()).start();
}
}
------------------------使用Callable和Future创建线程---------------------
和Runnable接口不一样,Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能要强大。
》call()方法可以有返回值
》call()方法可以声明抛出异常
Java5提供了Future接口来代表Callable接口里call()方法的返回值,并且为Future接口提供了一个实现类FutureTask,这个实现类既实现了Future接口,还实现了Runnable接口,因此可以作为Thread类的target。在Future接口里定义了几个公共方法来控制它关联的Callable任务。
>boolean cancel(boolean mayInterruptIfRunning):视图取消该Future里面关联的Callable任务
>V get():返回Callable里call()方法的返回值,调用这个方法会导致程序阻塞,必须等到子线程结束后才会得到返回值
>V get(long timeout,TimeUnit unit):返回Callable里call()方法的返回值,最多阻塞timeout时间,经过指定时间没有返回抛出TimeoutException
>boolean isDone():若Callable任务完成,返回True
>boolean isCancelled():如果在Callable任务正常完成前被取消,返回True
介绍了相关的概念之后,创建并启动有返回值的线程的步骤如下:
1】创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象)。
2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值
3】使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)
4】调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
代码实例:
public class Main {
public static void main(String[] args){
MyThread3 th=new MyThread3();
//使用Lambda表达式创建Callable对象
//使用FutureTask类来包装Callable对象
FutureTask<Integer> future=new FutureTask<Integer>(
(Callable<Integer>)()->{
return 5;
}
);
new Thread(task,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程
try{
System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回
}catch(Exception e){
ex.printStackTrace();
}
}
}
2、sleep() 、join()、yield()有什么区别
答:sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态,该方法既可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。
wait() :
wait()方法需要和notify()及notifyAll()两个方法一起介绍,这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用,也就是说,调用wait(),notify()和notifyAll()的任务在调用这些方法前必须拥有对象的锁。注意,它们都是Object类的方法,而不是Thread类的方法。
wait()方法与sleep()方法的不同之处在于,wait()方法会释放对象的“锁标志”。当调用某一对象的wait()方法后,会使当前线程暂停执行,并将当前线程放入对象等待池中,直到调用了notify()方法后,将从对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。当调用了某个对象的notifyAll()方法,会将对象等待池中的所有线程都移动到该对象的锁标志等待池。
除了使用notify()和notifyAll()方法,还可以使用带毫秒参数的wait(long timeout)方法,效果是在延迟timeout毫秒后,被暂停的线程将被恢复到锁标志等待池。
此外,wait(),notify()及notifyAll()只能在synchronized语句中使用,但是如果使用的是ReenTrantLock实现同步,该如何达到这三个方法的效果呢?解决方法是使用ReenTrantLock.newCondition()获取一个Condition类对象,然后Condition的await(),signal()以及signalAll()分别对应上面的三个方法。
yield() :
yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。
join() :
join()方法,让调用线程在当前线程对象上进行等待。当线程执行完成后,被等待的线程会在退出前调用notifyAll()通知所有的等待线程继续执行。
3、说说 CountDownLatch 原理
CountDownLatch也叫闭锁,是计数器自减的一种闭锁,某线程阻塞,对一个计数器自减到0,此线程被唤醒。在JDK1.5被引入,允许一个或多个线程等待其他线程完成操作后再执行。
CountDownLatch内部会维护一个初始值为线程数量的计数器,主线程执行await方法,如果计数器大于0,则阻塞等待。当一个线程完成任务后,计数器值减1。当计数器为0时,表示所有的线程已经完成任务,等待的主线程被唤醒继续执行。
CountDownLatch是一种共享锁,通过await()方法与countDown()两个方法实现自身的功能。
await() 实现是由主线程执行await方法,tryAcquireShared方法中如果state不等于0,返回-1,则加入到等待队列中,主线程通过LockSupport.park(this)被挂起。
countdown() 委托sync实现state的减1操作,即通过unsafe.compareAndSwapInt方法设置state值。如果state为0,通 过LockSupport.unpark唤醒await方法中挂起的主线程。
4、说说 CyclicBarrier 原理 参考
答:https://www.cnblogs.com/nullzx/p/5271964.html
5、说说 Semaphore 原理 参考
答:https://blog.csdn.net/coslay/article/details/45176063
6、说说 Exchanger 原理 参考
答:https://blog.csdn.net/chenssy/article/details/72550933
7、说说 CountDownLatch 与 CyclicBarrier 区别
答: 1、CountDownLatch简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。
2、cyclicBarrier是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行!
3、CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
4、CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。如果被中断返回true,否则返回false。
8、Java中用到的线程调度算法是什么 参考
答: https://www.jianshu.com/p/3f6b26ee51ce
9、什么是多线程中的上下文切换
答:
10、你对线程优先级的理解是什么
答
11、什么是线程调度器 (Thread Scheduler) 和时间分片 (Time Slicing)
答
12、ThreadLocal 原理分析
答 https://www.cnblogs.com/dolphin0520/p/3920407.html
13、ThreadPool用法与优势
答
14、讲讲线程池的实现原理 参考
答 https://blog.csdn.net/mine_song/article/details/70948223
15、线程池的几种方式与使用场景
答
16、线程池中submit() 和 execute()方法有什么区别?
答
17、线程池中的coreNum和maxNum有什么不同
答
18、在不同的业务场景中,线程池参数如何设置?
答
19、线程池的关闭方式有几种,各自的区别是什么
答
20、newCache 和 newFixed 有什么区别?简述原理。构造函数的各个参数的含义是什么,比如 coreSize, maxsize 等
答
21、线程的生命周期
答
22、多线程中的忙循环是什么
答
23、线程和进程有什么区别?进程间如何通讯,线程间如何通讯?
答
24、什么是多线程环境下的伪共享(false sharing)
答
25、同步和异步有何异同,在什么情况下分别使用他们?举例说明
答
26、启动一个线程是调用 run() 还是 start() 方法?start() 和 run() 方法有什么区别
答
27、调用start()方法时会执行run()方法,为什么不能直接调用run()方法
答
28、sleep() 方法和对象的 wait() 方法都可以让线程暂停执行,它们有什么区别
答
29、Java 中如何停止一个线程
答
30、stop() 和 suspend() 方法为何不推荐使用
答
31、如何在两个线程间共享数据
答
32、如何让正在运行的线程暂停一段时间
答
33、什么是线程组,为什么在Java中不推荐使用
答
34、你是如何调用 wait(方法的)?使用 if 块还是循环?为什么
答
35、有哪些不同的线程生命周期
答
36、线程状态,BLOCKED 和 WAITING 有什么区别
答
锁机制
1、说说线程安全问题
答
2、volatile 实现原理 参考
答 http://www.importnew.com/23520.html
https://www.jianshu.com/p/157279e6efdb
3、synchronize 实现原理 参考
答 http://www.importnew.com/29031.html
https://www.jianshu.com/p/19f861ab749e
4、synchronized 与 lock 的区别?Lock 接口比 synchronized 块的优势是什么?
答
5、什么场景下可以使用 volatile 替换 synchronized
答
6、CAS乐观锁
答
7、ABA问题
答
8、什么是乐观锁(Optimistic Locking)?如何实现乐观锁?如何避免ABA问题,乐观锁的业务场景
答
9、ReentrantLock 实现原理 参考
答
10、synchronized和ReentrantLock 有什么不同
答
11、什么是AQS? 参考
答 https://www.jianshu.com/p/c790f2b4891c
https://www.cnblogs.com/chengxiao/archive/2017/07/24/7141160.html
12、CAS的实现原理么?参考
答
13、ReadWriteLock是什么?
答 https://blog.csdn.net/qq_19431333/article/details/70568478
https://www.jianshu.com/p/9f98299a17a5
14、锁机制有什么用
答
15、解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁
答
16、什么时候应该使用可重入锁
答
17、简述锁的等级方法锁、对象锁、类锁
答
18、Java中活锁和死锁有什么区别?
答
19、什么是死锁(Deadlock)?导致线程死锁的原因?如何确保 N 个线程可以访问 N 个资源同时又不导致死锁
答
20、死锁与活锁的区别,死锁与饥饿的区别
答
21、怎么检测一个线程是否拥有锁
答
22、如何实现分布式锁
答
23、有哪些无锁数据结构,他们实现的原理是什么
答
24、读写锁可以用于什么应用场景
答
25、有T1,T2,T3三个线程,怎么确保它们按顺序执行?怎样保证T2在T1执行完后执行,T3在T2执行完后执行
答
26、同步块内的线程抛出异常会发生什么
答
27、当一个线程进入一个对象的 synchronized 方法A 之后,其它线程是否可进入此对象的 synchronized 方法B
答
28、使用 synchronized 修饰静态方法和非静态方法有什么区别
答
29、如何从给定集合那里创建一个 synchronized 的集合
答