🔥对线面试官 - 线程入门第一课
面试官:能聊一聊线程吗?什么是线程?它和进程有什么区别吗?
派大星:假设一个程序例如:weChat.exe
这是一个程序,一个静态的概念,双击运行。而进程是相对于程序来说是一个动态的概念。作为进程里面最小的执行单元便是线程。通俗的讲一个程序里不同的执行路径就是线程
面试官:run 方法和 start 方法有什么区别?
派大星:run()
方法是一个方法调用。start()
方法是 Thread 类里的一个方法。start()方法会产生一个分支和主方法一同执行。
面试官:线程的几种状态可以简单说一说吗?
派大星:好的
New(新创建)
Runnable(可运行)里面有 ready 和 running 两个状态
Blocked(被阻塞)未获得锁的时候
Waiting(等待)调用
join()
、wait()
、part()
方法Timed Waiting(计时等待)时间结束的时候。比如:sleep(1000)
Terminated(被终止)
面试官:创建线程的几种方式?有了解吗?可以详细聊一聊吗?
派大星:好的。主要有以下几种方式:
继承
Thread
类,重写run
方法。实现
Runnable
接口,重写run
方法。当然,还有类似的变种方法:JDK8 的 lambda 表达式的写法。当然还可以通过线程池来启动
Executors.newCachedThread
当然这种底层也是采用上述两种方式实现的。
面试官:了解线程里的sleep()
、yield()
、join()``interrupt
方法吗?
派大星:sleep()
方法会让出 CPU 让其它线程执行,yield()
会让线程重新回到等待队列中让出 CPU 但是也有可能下次执行的还是当前线程,也就是让线程回到就绪状态
。join()
方法:假设 t1 线程执行到中途调用了t2.join()
这是 t1 需要等待 t2 执行完成之后才会继续执行下去,经常用来等待另外一个线程的结束。
这里就引出了一个经典的线程题:如何保证线程 t1、t2、t3 依次顺序执行完成。很简单:只需要在主线程中填加 t1.join() t2.join() t3.join() 。或者在 t1 线程中填加 t2.join(),在 t2 线程中填加 t3.join()即可实现。
interrupt
方法线程调用 interrupt 方法打断线程,然后通过方法 interrupted 方法,可以获取到打断信号。通过这个信号,可以在代码逻辑中停止线程。通过开关的方式打断异常时,需要定义一个 volatile 标识的变量,通过判断这个变量来打断线程
面试官:sleep、yield、wait、notify、notifyAll 是否释放锁?
派大星:
sleep 和 yield 方法都是不会释放锁的
调用 sleep() 方法使线程进入等待状态,等待休眠时间达到,而调用我们的 yield() 方法,线程会进入就绪状态,也就是 sleep()需要等待设置的时间后才会进行就绪状态,而 yield 会立即进入就绪状态
wait、notify 和 notifyAll 都会释放锁
wait 方法执行后会立即释放锁,等待被唤醒的时候会重新持有锁 notify 和 notifyAll 也会释放锁,但是不是立即释放锁,执行完 notify/notifyAll 方法后会立即通知其它正在等待的线程,但不是立即释放锁,而是会等到其 synchronized 内中的代码全部执行完之后,才会释放锁。所以我们一般都时在我们 synchronized 内的最后才会调用 notify/notifyAll
面试官:wait 与 notify 为什么是 Object 的成员方法?
派大星:
我们都知道,synchronized 关键字可以加在任何对象的成员函数上,任何对象也都可以成为锁。那么,wait() 和 notify() 这样普及,Object 又是所有类的基类,那么 wait() 和 notify() 放在 Object 里面最合适不过。wait 和 nofity 不是常见的普通 java 方法或同步工具,在 Java 中它们更多的是实现两个线程之间的通信机制。如果不能通过类似 synchronized 这样的 Java 关键字来实现这种机制,那么 Object 类中就是定义它们最好的地方,以此来使任何 Java 对象都可以拥有实现线程通信机制的能力。
记住 synchronized 和 wait,notify 是两个不同的问题域,并且不要混淆它们的相似或相关性。 同步类似竞态条件,是提供线程间互斥和确保 Java 类的线程安全性的,而 wait 和 notify 是两个线程之间的通信机制。
另一个原因:每个对象都可以作为锁
在 Java 中,为了进入临界区代码段,线程需要获得锁并且它们等待锁可用,它们不知道哪些线程持有锁而它们只知道锁是由某个线程保持,它们应该等待锁而不是知道哪个线程在同步块内并要求它们释放锁。 这个比喻适合等待和通知在 object 类而不是 Java 中的线程。
如有问题,欢迎加微信交流:w714771310,备注- 技术交流 。或关注微信公众号【码上遇见你】。
版权声明: 本文为 InfoQ 作者【派大星】的原创文章。
原文链接:【http://xie.infoq.cn/article/4960cda6be967a819ccbcdd20】。
本文遵守【CC BY-NC-ND】协议,转载请保留原文出处及本版权声明。
评论