深入理解多线程____javaSE基础回顾

我是小柴,回顾学习java基础差不多有两个月了,个人感觉学习一门语言最可贵的就是坚持,做任何一件事最大的难题不是入手难易程度,而是自己能不能坚持走下去,我曾经听一位大牛说过,如何把你学到的东西彻底掌握?方法就是把你所学到的东西再传授另一个人,那怎么办呢,我们不可能回家拉着小学文化程度的父母谈JDK虚拟机,拿着计算机概论对着奶奶聊人工智能大数据吧;所以我决定在自己学习完SE基础后养成每周一篇博客的习惯,目的是对自己学过的东西进行复习总结,也对自己学习过程一个监督,一周一篇,一年48篇博客,即使自己日后没有成为互联网大牛也没关系,这也是自己成长路上写实,对于我来说是一种宝贵的财富;闲话不多说马上进入主题——深入浅聊聊我们的多线程.
多线程是javaSE里的重点部分,也是企业hr比较重视的考察类容,由于我前段时间学到了数据库,所以我准备以倒叙的方式从后往前复习基础内容.

首先我们先抛出几个问题:
1.进程与线程的关系
一个进程至少包含一个线程也可以有多个线程,线程是进程中的一个单位(执行路径).
一个程序运行至少有一个进程,一个进程中也可以包含多个线程

2.多线程两种实现方式
继承thread类重写run方法 开启线程子类调用start方法让线程程序执行,告诉jvm调用线程中的run方法
实现runnable接口的实现类,重现run方法将实现类传给thread对象的构造方法,开启线程调用start方法运行run
方法.(每创造出一个thread对象就开启了一个线程;而run方法里的方法体就是我们开启线程后希望线程去单独执行的代码操作)

3.多线程两种实现方式的区别
一个子类是继承父类thread,子类重写run;另一个是创建实现接口runnable的实现类;实现类重写run方法.
区别:第一种thread 的子类封装了线程执行内容在重写run里面;第二种做到对象与方法内容分离开来,更加符合面向对象思想,减少了类与类之间的耦合性,避免的单继承的局限性(推荐第二种)
runnable接口不是线程类,而是线程运行的目标类,想以线程的方式走run方法,必须依靠thread.

4.线程池的原理
开启指定个数的线程 存在一个集合内部等待开启执行,假如任务数大于线程池内线程个数,多余的任务将等待最先开始执行的线程执行结束 继续进行下一个任务

*a:进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,
即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。

线程的概念
线程:线程是进程中的一个执行单元(执行路径),负责当前进程中程序的执行,
一个进程中至少有一个线程。一个进程中是可以有多个线程的,
这个应用程序也可以称之为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程.

什么是多线程呢?
一个程序中有多个线程在同时执行。
一个核心的CPU在多个线程之间进行着随即切换动作,由于切换时间很短(毫秒甚至是纳秒级别),导致我们感觉不出来
感觉就是多个线程在同时运行.
例如:我们电脑的360安全卫士软件,我可以同时操作三个动作,我可以先启动查杀木马的功能,然后启动垃圾清理的功能还启动优化加速,每个功能代表着一个线程,三个功能同时在运行.

线程的运行模式
线程的运行模式
a:分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

b:抢占式调度
 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

 大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我们上课一边使用编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是在同时运行,”感觉这些软件好像在同一时刻运行着“。

 实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。
 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。

创建新执行线程有两种方法。

 a:一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象,调用start方法:启动一个新的线程,然后虚拟机调用新线程的run方法 。run方法相当于其他线程的main方法。
 b:另一种方法是声明一个实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,调用start方法:启动一个新的线程,然后虚拟机调用新线程的run方法 。

a:
这里写图片描述
这里写图片描述

b:这里写图片描述
这里写图片描述
问题1:为什么要继承Thread,而不直接创建thread对象直接调用start()方法?
thread类描述线程,具有线程应该有的功能,而直接创建thread对象调用start()方式运行的是thread类中的run方法,run里面没有具体操作内容,相当于开启一个没有执行任务的线程,线程不执行具体操作却占着内存空间. 我们这样理解:我花钱请人帮我干活,而我把人家请过来,却不告诉他我要他干什么活,然后他就一直坐在那等你安排任务;工资还是要给人家.

实现接口方式的好处
A:实现接口方式的好处
第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。
实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。
继承Thread类,线程对象和线程任务耦合在一起。
一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。
实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。
编程思想 (降低紧密性或者依赖性,创建线程和执行任务不绑定)
还有一个好处就是:runnable可以实现资源的共享.

线程的生命周期
新建(New):开启新的线程
可执行(Runnable):线程等待cpu执行
运行(Running):线程正在运行
阻塞(Blocking):线程的cpu资源被其他线程抢占进入待命状态.线程的sleep() wait()方法均可以导致线程进入等待状态.
死亡(Dead):线程执行的代码操作执行完毕,线程结束.

什么是线程池
线程池用于存贮多个线程,存储的线程执行不同的线程任务,执行结束后继续留在线程池中等待执行新的任务操作.线程池大大节省了系统内存,提高了内存的使用效率.

创建线程池
这里写图片描述

实现线程的Callable接口方式
/*
* 实现线程程序的第三个方式,实现Callable接口方式
* 实现步骤
* 工厂类 Executors静态方法newFixedThreadPool方法,创建线程池对象
* 线程池对象ExecutorService接口实现类,调用方法submit提交线程任务
这里我们用一个案例简单演示一下callable接口
<创建接口callable实现类>
创建接口callable实现类
<创建线程池>
这里写图片描述

线程安全问题
首先我们来了解一下什么是线程安全问题;安全问题志发生在多线程中,单线程不存在安全问题;为什么呢? 当开启多个线程处理同一个对象中的数据时,会发生的一种问题.
此时小柴举个例子: 我们有3个人去食堂打饭,食堂打饭点我们看成一个共享对象,打饭点里面的便当我们看成对象的数据;三个同学我们看成三个线程,我们去食堂的任务就是去吃饭,这个任务就是我们run方法,假如打饭点正好只有三分便当,而我们的理想的效果就是三个同学去食堂都要吃到便当,这时,第一位同学拿到便当后假设他在0.5s内把便当吃完又插队到第二位同学身后又拿走了一份便当吃掉了,而第三位同学此时没有便当可以分配,所以第三位同学中午没有吃到饭,这时的结果就偏离了我们的预期效果,这种现象称之为安全问题.

Synchronized 关键字
为了解决多线程所出现的安全问题;我们引入一个关键字Synchronized ;为了防止共享对象在并发访问出现错误
,确保共享对象在同一时刻只能被一个线程访问,这种处理机制称为“线程同步”或“线程互斥”。Java中的“线程同步”基于“对象锁”的概念.

同步代码块
同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

如何理解同步代码块?
我们再以上面的例子做出解释: 由于发现部分同学会有插队行为,我们推出一种方案,发明一种打饭专用的渠道;一次只能进入一个同学,进入渠道打饭的同学拿到一个锁,用锁将进入渠道的入口锁起来,等待他拿到便当后 再把锁打开离开渠道,锁将放回原位,下一个进入渠道的人可以再次拿到锁,这时后面的人就不能插队保证到了每位同学都能拿到便当.

让我们来用代码具体演示下同步代码块的操作

这里写图片描述

1、wait和sleep的区别
sleep是thread类的方法,wait是object类的方法
sleep有睡眠时间限制 wait等待没有时间限制
wait释放同步锁 sleep不释放同步锁
wait notify notifyall只能在同步代码块类使用 而sleep可以在任意位置使用
(补充)wait() notify()方法必须是锁对象才能调用!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值