重踏学习Java路上_Day23(多线程)
1:多线程(理解)
(1)多线程:一个应用程序有多条执行路径
进程:正在执行的应用程序
线程:进程的执行单元,执行路径
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径
多进程的意义?
提高CPU的使用率
多线程的意义?
提高应用程序的使用率
(2)Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
(3)多线程的实现方案(自己补齐步骤及代码 掌握)
A:继承Thread类
步骤:
A:自定义类MyThread继承Thread类。
B:MyThread类里面重写run()?
为什么是run()方法呢?
不是类中的所有代码都需要被线程执行的。
而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
C:创建对象
D:启动线程
B:实现Runnable接口(推荐使用,由于Java是单继承多实现,所以用第一种方法会造成该类没有办法继承其他类,或必须要让父类也实现该线程,这样是不行的)
步骤:
A:自定义类MyRunnable实现Runnable接口
B:重写run()方法
C:创建MyRunnable类的对象
D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
面试题:
为什么要重写run()方法
该类要重写run()方法,为什么呢?
不是类中的所有代码都需要被线程执行的。
而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
启动线程使用的是那个方法
start()
线程能不能多次启动
不能
// MyThread my = new MyThread();
// my.start();
// // IllegalThreadStateException:非法的线程状态异常
// // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
// my.start();
run()和start()方法的区别
run():仅仅是封装被线程执行的代码,直接调用是普通方法
start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
(4)线程的调度和优先级问题
A:线程的调度
a:分时调度
b:抢占式调度(Java采用的是该调度方式)
B:获取和设置线程优先级
a:默认是5
b:范围是1-10,最高10,最低1
(5)线程的控制(常见方法)
A.线程休眠(从运行状态转入阻塞,恢复后回到就绪状态,等待CPU的分配资源)
public static void sleep(long millis)
B.线程加入(注意API解释:等待该线程终止。但实际意思是,调用该方法的线程会运行,而放置该代码,调用该语句的线程会阻塞,等到该方法的线程执行完毕,主线程(即放置代码的线程)才会回到就绪状态)
public final void join()
C.线程礼让(暂停当前正在执行的线程对象,并执行其他线程。其实是暂停了一下,就回到就绪状态,让其他线程有机会使用CPU,减少因单一线程抢占使用过多,其他线程无法执行,达到相对平衡,但只能是相对,不可能达到绝对平衡)
public static void yield()
D.后台线程
public final void setDaemon(boolean on)(调用该方法的线程会变成后台线程,或叫守护线程。当所有非守护线程执行完后,守护进程也会接着消失,不管守护线程时候执行完他所需要执行的代码)
E.中断线程
public final void stop() (太暴力,不建议使用,由于执行了这个方法的线程马上终止所有操作,它后面的所有代码都不会执行,所以很容易会出现其他线程由于你的终止而产生崩毁)
public void interrupt() (推荐使用,调用此方法的线程会抛出一个异常,然后在catch处捕获处理,最后执行后面的代码,以后关闭线程,这样比较好,因为是比较完善的执行退出机制)
F.Thread类的基本获取和设置方法
public final String getName()
public final void setName(String name)
其实通过构造方法也可以给线程起名字
思考:
如何获取main方法所在的线程名称呢?
public static Thread currentThread()
这样就可以获取任意方法所在的线程名称
Thread.currentThread.setName("啦啦");
G.如何设置和获取线程优先级
public final int getPriority()
public final void setPriority(int newPriority)
(6)线程的生命周期(参照 线程生命周期图解.bmp)
A:新建 -- 线程创建
B:就绪 -- 有使用权,没有执行权
C:运行 -- 有使用权,有执行权
D:阻塞 -- 没有执行权,没有使用权
E:死亡 -- 退出线程
(7)电影院卖票程序的实现
A:继承Thread类
B:实现Runnable接口
(8)电影院卖票程序出问题
A:为了更符合真实的场景,加入了休眠100毫秒。
B:卖票问题
a:同票多次
b:负数票
(9)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
(10)同步解决线程安全问题
A:同步代码块
synchronized(对象){
需要被同步的代码;
}
这里的锁对象可以是任意对象。
B:同步方法
这里的锁对象是this
private synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
C:静态同步方法
这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
private static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
(11)回顾以前的线程安全的类
A:StringBuffer
B:Vector
C:Hashtable
D:如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可。
思考题:
jvm虚拟机的启动是单线程的还是多线程的?
多线程的。
原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。
现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。
进程:
正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
线程:
是进程中的单个顺序控制流,是一条执行路径
一个进程如果只有一条执行路径,则称为单线程程序。
一个进程如果有多条执行路径,则称为多线程程序。
大家注意两个词汇的区别:并行和并发。
前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。
Java程序的运行原理:
由java命令启动JVM,JVM启动就相当于启动了一个进程。
接着有该进程创建了一个主线程去调用main方法。
--------------------------------------------------------------------------------------------------------------------------------------
1:要想了解多线程,必须先了解线程,而要想了解线程,必须先了解进程,因为线程是依赖于进程而存在。
2:什么是进程?
通过任务管理器我们就看到了进程的存在。
而通过观察,我们发现只有运行的程序才会出现进程。
进程:就是正在运行的程序。
进程是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
3:多进程有什么意义呢?
单进程的计算机只能做一件事情,而我们现在的计算机都可以做多件事情。
举例:一边玩游戏(游戏进程),一边听音乐(音乐进程)。
也就是说现在的计算机都是支持多进程的,可以在一个时间段内执行多个任务。
并且呢,可以提高CPU的使用率。
问题:
一边玩游戏,一边听音乐是同时进行的吗?
不是。因为单CPU在某一个时间点上只能做一件事情。
而我们在玩游戏,或者听音乐的时候,是CPU在做着程序间的高效切换让我们觉得是同时进行的。
4:什么是线程呢?
在同一个进程内又可以执行多个任务,而这每一个任务我就可以看出是一个线程。
线程:是程序的执行单元,执行路径。是程序使用CPU的最基本单位。
单线程:如果程序只有一条执行路径。
多线程:如果程序有多条执行路径。
5:多线程有什么意义呢?
多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。
程序的执行其实都是在抢CPU的资源,CPU的执行权。
多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。
我们是不敢保证哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。