面试必备——Java多线程与并发(一)
1.进程和线程的
(1)由来
1)串行
2)批处理
存在问题:
3)进程
4)线程
(2)区别
- 所有与进程相关的资源,都被记录在PCB(进程控制块)中
进程是抢占处理器的调度单位;线程属于某个进程,共享其资源
线程只由堆栈寄存器、程序计数器和TCB组成
总结
- 线程不能看做独立应用,而进程可看做独立应用
- 进程有独立的地址空间,相互不影响,线程只是进程的不同执行路径
- 进程数据分开,共享复杂,同步简单;线程共享简单,同步复杂
- 线程没有独立的地址空间,多进程的程序比多线程程序健壮(进程出现问题不会影响其他进程,可靠高;一个线程挂掉,整个进程也会挂掉,可靠低)
- 进程的切换比线程的切换开销大(进程单独占有一定的内存地址空间,进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小)
(3)JAVA进程和线程的关系
- Java对操作系统提供的功能进行封装,包括进程和线程
- 运行一个程序会产生一个进程,进程包含至少一个线程
- 每个进程对应一个JVM实例,多个线程共享JVM里的堆,JVM是多线程的
- Java采用单线程编程模型,程序会自动创建主线程
- 主线程可以创建子线程,原则上要后于子线程完成执行,因为要执行各种关闭动作
2.线程的start和run的区别
- 调用start()方法会创建一个新的子线程并启动
- run()方法只是Thread的一个普通方法的调用
3.Thread和Runnable是什么关系
- Thread是实现了Runnable接口的类,通过Thread的start()方法可以给Runnable的run()方法附上多线程的特性
- 因Java类的单一继承原则,推荐多使用Runnable接口(为了提升系统的可拓展性,通过使业务类实现Runnable接口,将业务逻辑封装在run方法里,后续可以给普通类附上多线程的特性)
4.如何实现处理线程的返回值
(1)主线程等待法:实现简单,我们可以通过实现循环等待的逻辑;缺点是变量多的时候会显得臃肿,无法精准控制

1 public class CycleWait implements Runnable {
2
3 private String value;
4
5 @Override
6 public void run() {
7 try {
8 Thread.currentThread().sleep(5000);
9 } catch (InterruptedException e) {
10 e.printStackTrace();
11 }
12 value = "we have date now";
13 }
14
15 public static void main(String[] args) throws InterruptedException {
16 CycleWait cw = new CycleWait();
17 Thread t = new Thread(cw);
18 t.start();
19 //当值为null的时候一直循环,直到有值时才退出循环
20
21 while (cw.value == null) {
22
23 Thread.currentThread().sleep(100);
24
25 }
26 System.out.println("value:" + cw.value); // 没有前面的循环,可能取出的值为null
27 }
28 }
(2)使用Thread类的join()阻塞当前线程以等待子线程处理完毕:实现更简单,缺点是力度不够细,无法精确控制

1 public static void main(String[] args) throws InterruptedException {
2 CycleWait cw = new CycleWait();
3 Thread t = new Thread(cw);
4 t.start();
5 t.join();
6 System.out.println("value:" + cw.value);
7 }
(3)通过Callable接口实现:JDK5.0新增的,具体可以通过FutureTask或线程池获取

1 public class myCallable implements Callable {
2 @Override
3 public String call() throws Exception {
4 String value = "test";
5 System.out.println("Ready to work");
6 Thread.currentThread().sleep(3000);
7 System.out.println("task done");
8 return value;
9 }
10 }
- FutureTask

1 public static void main(String[] args) throws ExecutionException, InterruptedException {
2 FutureTask<String> ft = new FutureTask<String>(new myCallable());
3 new Thread(ft).start();
4 if (!ft.isDone()) {
5 System.out.println("task has not finished, please wait!");
6 }
7 System.out.println("task reture:" + ft.get());
8 }
- 线程池

1 public static void main(String[] args) {
2 ExecutorService executorService = Executors.newCachedThreadPool();
3 Future<String> future = executorService.submit(new myCallable());
4 if (!future.isDone()) {
5 System.out.println("task has not finished, please wait!");
6 }
7 try {
8 System.out.println("task reture:" + future.get());
9 } catch (InterruptedException e) {
10 e.printStackTrace();
11 } catch (ExecutionException e) {
12 e.printStackTrace();
13 } finally {
14 executorService.shutdown();
15 }
16 }
运行结果
1 task has not finished, please wait!
2 Ready to work
3 task done
4 task reture:test
5.线程的状态(6个)
(1)新建(New):创建后尚未启动的线程的状态
(2)运行(Runnable):包含Running和Ready(Running:正在执行;Ready:等待CPU分配执行时间)
(3)无限期等待(Waiting):不会被分配CPU执行时间,需要显示被唤醒
- 没有设置Timeout参数的Object.wait()方法
- 没有设置Timeout参数的Thread.join()方法
- LockSupport.park()方法
(4)限期等待(Timed Waiting):在一定时间后由系统自动唤醒
- Thread.sleep()方法
- 设置了Timeout参数的Object.wait()方法
- 设置了Timeout参数的Thread.join()方法
- LockSupport.parkNanos()方法
- LockSupport.parkUntil()方法
(5)阻塞(Blocked):等待获取排它锁
(6)结束(Terminated):已终止线程的状态,线程已经结束执行
6.sleep和wait的区别
(1)基本差别
- sleep是Thread类的方法,wait是Object类中定义的方法
- sleep()方法可以在任何地方使用
- wait()方法只能在synchronized方法或synchronized块中使用
(2)最主要的本质区别
- Thread.sleep只会让出CPU,不会释放锁
- Object.wait不仅会让出CPU,还会释放锁(这个方法要写在synchronized里面,因为要获得锁,才能释放锁)
7.notify和notifyall的区别
(1)需要先了解的两个概念
- 锁池EntryList
- 等待池WaitSet
(2)区别
- notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会
- notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会
8.yield相关
当调用Thread.yield()函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示,该方法不释放锁。

1 public static void main(String[] args) {
2 Runnable yieldTask = () -> {
3 for (int i = 0; i <= 10; i++) {
4 System.out.println(Thread.currentThread().getName() + i);
5 if (i == 5){
6 Thread.yield(); // 暗示线程调度器愿意让出CPU使用,但最终决定权还是在线程调度器中
7 }
8 }
9 };
10 Thread thread1 = new Thread(yieldTask,"A");
11 Thread thread2 = new Thread(yieldTask,"B");
12 thread1.start();
13 thread2.start();
14 }
9.interrupt相关
(1)设计理念
(2)如何中断线程
1)已经被抛弃的方法
- 通过调用stop()方法停止线程
- 通过调用suspend()和resume()方法
2)目前使用的方法
- 如果线程处于被阻塞状态,那么线程立即退出被阻塞状态,并抛出一个InterruptedException异常
- 如果线程处于正常活动状态,那么会将该线程的中断标志设置为true。被设置中断标志的线程将继续正常运行,不受影响
- 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程
- 调用Thread.interrupted() 方法后线程恢复非中断状态,即Thread.currentThread().isInterrupted()是false
面试必备——Java多线程与并发(一)的更多相关文章
- 面试必备——Java多线程与并发(二)
1.synchroized相关(锁的是对象,不是代码) (1)线程安全问题的主要原因 存在共享数据(也称临界资源) 存在多线程共同操作这些共享数据 解决:同一时刻有且只有一个线程在操作共享数据,其他线 ...
- 互联网校招面试必备——Java多线程
本文首发于我的个人博客:尾尾部落 本文是我刷了几十篇一线互联网校招java后端开发岗位的面经后总结的多线程相关题目,虽然有点小长,但是面试前看一看,相信能帮你轻松啃下多线程这块大骨头. 什么是进程,什 ...
- JAVA多线程和并发基础面试问答(转载)
JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...
- [转] JAVA多线程和并发基础面试问答
JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...
- JAVA多线程和并发基础面试问答
转载: JAVA多线程和并发基础面试问答 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对 ...
- 【多线程】JAVA多线程和并发基础面试问答(转载)
JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...
- (转)JAVA多线程和并发基础面试问答
JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...
- JAVA多线程和并发基础面试问答【转】
JAVA多线程和并发基础面试问答 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰 ...
- 17、JAVA多线程和并发基础面试问答
JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...
随机推荐
- 2020牛客暑期多校训练营(第四场)BCFH
BCFH B. Basic God Problem 题意 给出c和n,求fc(n). 题解 递归到最后 fc 函数肯定等于1,那么就变成了求c被乘了几次,只要找到 x 最多能被分解成多少个数相乘就好了 ...
- Codeforces Round #531 (Div. 3) E. Monotonic Renumeration (构造)
题意:给出一个长度为\(n\)的序列\(a\),根据\(a\)构造一个序列\(b\),要求: 1.\(b_{1}=0\) 2.对于\(i,j(i\le i,j \le n)\),若\(a_{i ...
- Proud Merchants HDU - 3466 01背包&&贪心
最近,我去了一个古老的国家.在很长一段时间里,它是世界上最富有.最强大的王国.结果,这个国家的人民仍然非常自豪,即使他们的国家不再那么富有.商人是最典型的,他们每个人只卖一件商品,价格是Pi,但是如果 ...
- centos7源码编译安装lamp/lnmp
centos7源码编译安装lamp/lnmp 进程:是包工头(相当于是个门,只管开门关门,不管门内的事儿) 线程:是各种工种(cpu调度的是线程) 进程 是一件事情, 线程 是 同一个时间范围内 同时 ...
- 二进制安装kubernetes(六) kube-proxy组件安装
Kube-Proxy简述 参考文献: https://ywnz.com/linuxyffq/2530.html 运行在每个节点上,监听 API Server 中服务对象的变化,再通过管理 IPtabl ...
- MySQL数据库系列(三)- MySQL常用引擎MyISAM和InnoDB区别详解
概述 InnoDB:在MySQL 5.5及之后的版本,InnoDB是MySQL默认的事务型引擎,也是最重要和使用最广泛的存储引擎.它被设计成为大量的短期事务,短期事务大部分情况下是正常提交的,很少被回 ...
- C++中二维数组作为函数参数
在平时,我们经常会遇到将整个数组作为函数参数的情况,一维数组的情况,就是用数组名当形参和实参,传递的是数组的首地址.二维数组我们用的也很多,但是总是有各种问题,今天我总结一下 有个很重要的一点,字符串 ...
- 全局ID生成--雪花算法
分布式ID常见生成策略: 分布式ID生成策略常见的有如下几种: 数据库自增ID. UUID生成. Redis的原子自增方式. 数据库水平拆分,设置初始值和相同的自增步长. 批量申请自增ID. 雪花算法 ...
- Creative Commons : CC (知识共享署名 授权许可)
1 https://creativecommons.org/ Keep the internet creative, free and open. Creative Commons help ...
- React + GraphQL 2020 速成课程
React + GraphQL 2020 速成课程 technologies React (to build our user interface) GraphQL (to get and chang ...