多线程相关知识点总结
多线程相关知识点总结
1. 线程的概念:
在早期的操作系统中并没有线程的概念,进程是拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。
后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID,当前指令指针PC,寄存器和堆栈组成。而进程由内存空间(代码,数据,进程空间,打开的文件)和一个或多个线程组成。
进程与线程的区别
线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;
调度和切换:线程上下文切换比进程上下文切换要快得多
2. 线程的生命周期:
新建 New — 就绪 Runnable — 运行 Running — 阻塞 Blocked — 死亡 Dead
新建 New:就是刚使用new方法,new出来的线程;
就绪 Runnable:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
运行 Running:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;
阻塞 Blocked:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;
死亡 Dead:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;
线程进入阻塞状态的原因:
1.等待I/O流的输入输出
2.等待网络资源,即网速问题
3.调用sleep()方法,需要等sleep时间结束
4.调用wait()方法,需要调用notify()唤醒线程
5.其他线程执行join()方法,当前线程则会阻塞,需要等其他线程执行完。
线程进入死亡状态的原因:
1.线程正常完成工作
2.调用stop()方法,强行停止线程
3.外部原因中断线程
3. 实现现线程的三种方式:
1.继承Thread:
自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程;
代码示例:
public class ThreadDemo extends Thread{@Overridepublic void run() {//run方法线程体for (int i = 0; i < 20; i++) {System.out.println("run: 我在吃饭====" + i);}}//mainpublic static void main(String[] args) {//创建一个线程对象ThreadDemo testThread = new ThreadDemo();//调用start()开启线程testThread.start();for (int i = 0; i < 50; i++) {System.out.println("main:我在看电影====" + i);}}
}
执行结果:
可以看出,main()方法中的程序和run()方法中的程序交替执行
此时,我们将statr()方法,改成run()方法,再看结果:
可以看出,run()方法执行完之后,main()方法才开始执行:
综上可得出:
run() 和 start() 的区别:
2.实现Runnable:
推荐使用Runnable对象,因为Java单继承的局限性
自定义线程类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动对象;
代码示例:
public class RunnableDemo implements Runnable{@Overridepublic void run() {//run方法线程体for (int i = 0; i < 20; i++) {System.out.println("run: 我在吃饭====" + i);}}public static void main(String[] args) {//创建一个线程对象ThreadDemo testThread = new ThreadDemo();//调用start()开启线程testThread.start();for (int i = 0; i < 50; i++) {System.out.println("main:我在看电影====" + i);}}
}
执行结果:
3.实现Callable:
可以定义返回值
可以抛出异常
实现Callable有两种:
1. 使用线程池:
代码示例:
public class CallableDemo implements Callable<Boolean> {@Overridepublic Boolean call() throws Exception {//run方法线程体for (int i = 0; i < 20; i++) {System.out.println("run: 我在吃饭====" + i);}return true;}public static void main(String[] args) throws ExecutionException, InterruptedException {CallableDemo callableDemo = new CallableDemo();//1.创建执行服务ExecutorService es = Executors.newFixedThreadPool(1);//2.执行提交Future<Boolean> r1 = es.submit(callableDemo);//3.获取结果Boolean res = r1.get();System.out.println(res);//4,关闭服务es.shutdown();}
}
执行结果:
2. 使用FutureTask包装:
代码示例:
public class CallableDemo2 implements Callable {@Overridepublic Object call() throws Exception {//run方法线程体for (int i = 0; i < 20; i++) {System.out.println("run: 我在吃饭====" + i);}return 666;}public static void main(String[] args) {CallableDemo2 testCallable = new CallableDemo2();//创建多个FutureTask对象,才能多次执行线程FutureTask futureTask1 = new FutureTask(testCallable);FutureTask futureTask2 = new FutureTask(testCallable);new Thread(futureTask1).start();new Thread(futureTask2).start();try {System.out.println(futureTask1.get());System.out.println(futureTask2.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}
执行结果:
剩余待完善。。。
wait()和 sleep()的区别:
线程休眠 线程礼让
join()的使用
线程的优先级
用户线程和守护线程
线程同步(线程锁 synchronized)
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制 synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可,但同时也会存在一些问题:
- 一个线程持有锁会导致其他所有需要此锁的线程挂起;
- 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换 和 调度延时,引起性能问题;
- 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引发新能问题;
同步块:sunchronized(Obj){}
Obj称之为 同步监视器
- Obj可以是任何对象,但是推荐使用共享资源作为同步监视器;
- 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class;
同步监视器的执行过程:
1.第一个线程访问,锁定同步监视器,执行其中的代码;
2.第二个线程访问,发现同步监视器被锁定,无法访问;
3.第一个线程访问完毕,解锁线程同步监视器;
4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问;
CopyOnWriteArrayList线程安全的集合
死锁
概念:
多个线程各自占有一些资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止的情形,叫做死锁。某一个同步块同时拥有"两个以上对象的锁"时,就可能发生"死锁"的问题。
产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用;
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺;
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;
只要想办法破掉以上的一个或者多个就可以避免死锁的产生!
Lock锁
ReentrantLock 可重入锁
synchronized 与 Lock 的对比:
- Lock是显式锁(需要手动开启和关闭),synchronized是隐式锁,出了作用域自动释放;
- Lock只有代码块锁,synchronized有代码块锁和方法锁;
- 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类);
- 优先使用顺序:Lock锁 > 同步代码块(已经进入了方法体,分配了相应资源) > 同步方法(在方法体之外)
生产者和消费者问题
多线程相关知识点总结相关推荐
- 并发与多线程相关知识点梳理
文章目录 并发和并行的概念 如何保证线程安全 1. 数据单线程内可见 2. 只读对象 3. 线程安全类 4. 同步与锁机制 什么是锁 线程同步 引用类型 ThreadLocal LeetCode 相关 ...
- 多线程的相关知识点(下)
多线程的相关知识点 12.死锁 死锁的四个条件: 互斥: 资源x在任意时刻只能被一个线程持有 占有且等待: 线程1占有资源x的同时等待资源y,并不释放x 不可抢占: 资源x一旦被线程1占有后,其他线程 ...
- Java多线程相关的几十个问题
转载来源:http://www.cnblogs.com/HadesFX/p/5333810.html , https://www.cnblogs.com/HadesFX/p/5333820.html ...
- labview csv文件处理_LabVIEW 相关知识点分类汇总
题图照片:Photo by Pixabay from Pexels 为了在知乎和小伙伴们一起更好进行LabVIEW相关知识与技术的讨论,特此制作了本知识点分类汇总供大家参考,分类采用先分块后分层的分而 ...
- ArrayList源码解析与相关知识点
ArrayList源码解析于相关知识点(超级详细) 文章目录 ArrayList源码解析于相关知识点(超级详细) ArrayList的继承关系 Serializable标记接口 Cloneable标记 ...
- ESB(企业服务总线)相关知识点总结
目录 一.什么是ESB 二.ESB解决了什么问题以及什么是HSB 三.市面上 ESB产品有哪些?如何选择 四. 如何实现ESB的各个功能 1.ESB的服务接入方式? 2.ESB的如何进行协议转换? 3 ...
- Redis 相关知识点
Redis 相关知识点 概述 为什么要用缓存 为什么用redis 用redis缓存了哪些东西 单线程redis为什么这么快 redis的数据类型和使用场景 redis 的过期策略都有哪些?内存淘汰机制 ...
- redis相关知识点讲解,redis面试题
redis相关知识点讲解,redis面试题 1. redis基本知识点 1.1 什么是redis? 1.2 redis的key的设计 1.3 redis的value数据类型有哪些? 1.3.1 str ...
- Java虚拟机垃圾回收相关知识点全梳理(下)
2019独角兽企业重金招聘Python工程师标准>>> 一.前言 上一篇文章<Java虚拟机垃圾回收相关知识点全梳理(上)>我整理分享了JVM运行时数据区域的划分,垃圾判 ...
最新文章
- pytorch torch.device类(表示在其上或将要分配torch.Tensor的设备)
- 可变参数的使用之va_arg的陷阱s
- .Net Core3.0 配置Configuration
- JS 中去除空格和换行的正则表达式写法
- Mobx | 强大的状态管理工具 | 可以用Mobx来替代掉redux
- Jsp+Servlet+Mysql实现的在线图书商城源码
- C语言strcmp函数使用及模拟
- 爬点今日头条街拍美女。。。
- linux 开发c工具箱,利用Windows10的Linux子系统搭建gcc/g++开发环境
- Laravel Guzzle封装
- 面试|详细分析ScheduledThreadPoolExecutor(周期性线程池)的原理
- 【新年福利】2019年值得一用的8款协作工具
- 一文了解加密游戏illuvium新玩法:探索神兽世界
- treeview demo
- HTTP之proxy
- 金蝶云星空对接打通旺店通·企业版采购入库查询接口与创建采购入库单接口
- git 2.33.1 访问服务器报Permission denied (publickey)
- 走进常熟东南相互电子,看AI如何深入产业让工厂更智能
- 基于Madplay的MP3音乐播放器
- mysql定时备份数据库-linux