黑马程序员------毕老师视频笔记第十一天------多线程(1)
来源:互联网 发布:冷情阁app网络错误 编辑:程序博客网 时间:2024/06/05 04:14
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
一.概述
要学习多线程,先要知道线程的概念,而学习线程,要先学习进程的概念。
什么是进程呢?正在执行的程序
直观感受一下
宏观上,进程是同时执行的,但是微观上,CPU一个时刻只能执行一个程序,CPU在做着快速的切换。
而在一个进程中,会有多条执行路径,例如迅雷
进程:是一个正在执行中的程序
每一个进程执行,都有一个执行的顺序,该顺序就是一个执行路径,或叫做执行情景,或者叫一个控制单元
线程:就是进程中真正执行的部分,就是进程中一个独立的控制单元
线程在控制着进程的执行
一个进程中至少有一个线程
JVM启动的时候会有一个进程java.exe,该进程中至少会有一个线程在负责者java程序的执行,而且这个线程运行的代码位于main方法中。
该线程称之为主线程。
扩展:其实更细节的说明JVM,JVM启动不只有一个线程,还有负责垃圾回收机制的线程
二.创建线程------继承Thread类
进程是系统创建的,那进程中的线程也是系统创建的,java只要调用系统的相关功能就能创建线程。java把相关的事物封装,成为Thread类。
(一个类形成为异常,继承Exception;想成为线程,继承Thread)
通过对API的查找,java已经提供了对线程这类事物的描述,就是Thread类,创建线程的第一种方式,就是继承Thread类,然后覆盖run方法。
为什么覆盖run方法呢?
public class Thread extends Objectimplements Runnable{}
run方法时实现Runnable接口中的方法
run方法中的内容就是新建的线程要执行的内容
步骤:
1.继承Thread类
2.覆盖run方法
3.调用start方法启动线程
class Demo extends Thread{//run必须是public的,它原来是接口Runnable中定义的public void run(){for (int i=0; i<100; i++){System.out.print("Demo ");}}}class ThreadDemo{public static void main (String [] args){//注意,不需要调用d.run();Demo d = new Demo();d.start();for (int i=0; i<100; i++){System.out.print("main ");}}}
发现运行结果每次都不同
因为多个线程都获取了CPU的执行权,CPU执行到谁,谁就运行
明确一点,在某一时刻,只能有一个程序运行(多核除外)
CPU在做着快速切换,以达到看上去是同时运行的效果
我们可以形象的把多线程的运行行为看做是多个线程在抢夺CPU的执行权
这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长时间,CPU说了算
(其实执行多长时间是可以控制的,但是过程还是比较麻烦的)
为什么要覆盖run方法呢?总结一下,就是
Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
也就是说,Thread类中的run方法是用于存储线程要运行的代码
主线程要运行的代码是存储在main方法中,这是JVM定义的
在主函数中写 d.run() 会怎么样呢?创建了线程,定义了要运行的功能,但是不会开启线程,这样就是一般的调用对象的方法,会在主函数中顺序执行
d.start(); 开启线程并执行run中的功能
start调用的是底层,开启了一个线程
三.线程运行状态
看一张老图
Thread类肯定调用了底层,java不会自己创建线程的,windows上跑的时候是windows系统帮忙创建的线程。
冻结又叫睡眠或等待,线程还活着,但是不动了
sleep(time),时间到了之后,线程就醒了(回到临时状态),继续执行,sleep就放弃了执行资格
wait(),线程活着,但是不唤醒的话,线程一直睡着,wait也会放弃执行资格
notify(),叫醒线程,wait之后notify,他才会醒,唤醒之后线程在临时状态
stop(),停止线程,线程消亡,每种状态都可以用stop把线程弄死
不用stop线程会消亡吗?会,执行完他就消亡了。
临时状态,阻塞状态,就绪状态,他们是一个状态
start一个线程之后,他也许不会马上执行,这时就处在这种状态,具备了运行资格,但没有执行权。
下面是毕老师的一张图
四.获取线程对象及名称
Thread;类中有setName方法和getName方法
用getName就可以得到线程名
线程都有自己默认的名称
Thread-0 Thread-1 等
这些名称可阅性不强,我们可以自己起setName(String name)
线程有一个可以传名称的构造函数Thread(String name)
所以子类中我们可以直接用 Demo(String name){super(name);}
Thread类中还有一个函数
static Thread currentThread() 返回当前正在执行的线程对象的引用。
我们可以调用它 Thread.currentThread()得到线程对象的引用
可以用this验证一下,他们是相同的
class Demo extends Thread{private String name;public void run(){System.out.println(getName());System.out.println(this.getName());System.out.println(Thread.currentThread().getName());System.out.println(this==Thread.currentThread());}Demo(String name){this.name = name;}Demo(){}}class ThreadDemo{public static void main (String [] args){Demo d1 = new Demo();Demo d2 = new Demo("second Thread");d1.start();d2.start();//这里没有创建ThreadDemo的对象,不能用this System.out.println(Thread.currentThread().getName());}}
五.创建线程的另一种方法
实现Runnable接口
步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法
将线程要运行的代码存放在该方法中
3.在main方法中通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runnable接口的子类对象传递给Thread类的构造函数呢?
因为,自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法,就必须明确该run方法所属的对象
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
实现方式和继承方式有什么区别呢?
实现方式的好处:避免了单继承的局限性,一个类本身有父类,怎么让他独立运行呢
在定义线程的时候建议使用实现方式
两种方式的区别;
继承Thread:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口子类的run方法中
Runnable接口就是在确立run方法存在的位置。
六.多线程的安全问题
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
解决办法:
对多条操作共享数据的语句,只能允许一个线程都执行完,在执行过程中,其他线程不可以参与执行。
java对于多线程的安全问题提供了专业的解决方式
同步代码块
synchronized(对象){需要被同步的代码}
对象是有标志位的,两位,一位允许线程进,一位阻止线程进,“锁旗标”
对象如同锁,持有锁的线程可以在同步代码块中执行,没有持有锁的线程即使获取了CPU的执行权,也进不去。
例举,火车上的卫生间
同步的前提:
1.必须要有两个或两个以上的线程
2.必须是多个线程使用同一个锁,也就是同一个对象
必须保证同步中只能有一个线程运行
可以建一个Object对象,当做锁,不用另外定义类
好处:解决了多线程的安全问题
弊端:多个线程都需要判断锁,较为消耗资源
同步函数
用synchronized关键字修饰函数
只能有一个线程进入函数,执行函数中的代码
同步函数和同步代码块是一样的机制,都有一个锁
非静态同步函数的锁是this
静态同步函数的锁Class对象(典型示例:单例设计模式的懒汉式)
死锁
一般出现在同步嵌套的情况,两个锁,持锁的线程之间都不放锁
死锁可能被“和谐”
(示例见下篇blog)
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
- 黑马程序员------毕老师视频笔记第十一天------多线程(1)
- 黑马程序员------毕老师视频笔记第十一天------多线程(2)
- 黑马程序员------毕老师视频笔记第十天------面向对象(异常下)
- 黑马程序员------毕老师视频笔记第十天------面向对象(面向对象练习题上)
- 黑马程序员------毕老师视频笔记第十天------面向对象(面向对象练习题下)
- 黑马程序员------毕老师视频笔记第十天------面向对象(包)
- 【黑马程序员】多线程(一) 第十一天
- 黑马程序员------毕老师视频笔记第十二天------多线程(3)
- 黑马程序员 —— Java多线程1 (第十一天)
- 黑马程序员--第十一天:多线程
- 黑马程序员---毕向东老师视频笔记(关于static)
- 黑马程序员---毕向东老师视频笔记(多态)
- 黑马程序员---毕向东老师视频笔记(继承)
- 黑马程序员------毕老师视频笔记第22天-----图形化编程(GUI)(1)
- 黑马程序员------毕老师视频笔记第23-24天------网络编程(1)
- 黑马程序员------张孝祥老师视频笔记------高新技术
- 黑马程序员--- 学习笔记(第十一天)
- 黑马程序员第十一天
- 基于内容的图像检索 概述
- 问:使用Application Loader上传ipa文件有什么好的经验?
- 完全卸载oracle11g步骤
- QT——QSqlQueryModel
- NoSQL数据库-MongoDB和Redis
- 黑马程序员------毕老师视频笔记第十一天------多线程(1)
- c语言打印九九乘法表
- Azure 网站上的 Java
- JS中offsetTop、clientTop、scrollTop、offsetTop各属性介绍
- 节约经费(dij)
- CodeIgniter 错误: In order to use the Session class you are required to set an encryption key
- ASPxGridView 后台选择多列
- dll导出的真正含义
- 获取鼠标所在窗体的PID