面试必备——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 ...
随机推荐
- zookper投票机制
前提:已经搭建好zookper集群 1.先开启编号为01的服务器 2.开启编号为02的服务器,状态为leader,编号为01的变成follower 3.开启编号为03的服务器,状态为follower ...
- Kubernetes-5-2:Harbor仓库的几种高可用方案与搭建
高可用Harbor搭建 思路及介绍 Harbor官方有推出主从架构和双主架构来实现Harbor的高可用及数据备份. 一.主从架构: 说白了,就是往一台Harbor仓库中push镜像,然后再通过这 ...
- Codeforces Round #630 (Div. 2)
题目链接:https://codeforces.com/contest/1332 A. Exercising Walk 可走的最远距离:左:x-x1,右:x2-x,下:y-y1,上:y2-y 如果可以 ...
- Educational Codeforces Round 87 (Rated for Div. 2) D树状数组加二分删除的值
Sample Input 5 4 1 2 3 4 5 -5 -1 -3 -1 Sample Output 3 思路,首先发现a[i]的值的范围是在1~n之间,每次插入我们可以直接把cnt[a[i]]+ ...
- Milk Patterns POJ - 3261 后缀数组
Farmer John has noticed that the quality of milk given by his cows varies from day to day. On furthe ...
- [Golang]-2 Map关联数组与下划线(_)的意义
目录 map 下划线(underscore) 用在import 用在返回值 用在变量 map map 是 Go 内置关联数据类型(在一些其他的语言中称为哈希 或者字典 ). func main() { ...
- OpenStack Train版-10.安装neutron网络服务(网络节点:可选)
可选:安装neutron网络服务节点(neutron01网络节点192.168.0.30)网络配置按照官网文档的租户自助网络 配置系统参数 echo 'net.ipv4.ip_forward = 1' ...
- Hexo准备---Node.js、Vue
Hexo准备---Node.js.Vue 安装node.js 1.下载node 配置node.js环境官网下载,一直next就好,非常方便. 下载官网: http://nodejs.cn/downlo ...
- 一篇文章图文并茂地带你轻松学会 HTML5 storage
html5 storage api localStorage 和 sessionStorage 是 html5 新增的用来存储数据的对象,他们让我们可以以键值对的形式存储信息. 为什么要有 stora ...
- leetcode 周赛 205 1576-5508-5509-5510
第四题比较难,看题解用并查集做比较简单,但是我觉得难度在想到用并查集,可能是最近做题少所以想不到吧. 1 替换所有的问号 class Solution { public: string modifyS ...