程序、进程、线程
程序--静态的概念 指令集
进程--动态的概念 操作系统调度程序执行 一个程序就是一个进程 占用内存
三部分组成 cpu、data、code
线程--在进程中多条执行路径
(1)多线程:一个应用程序有多条执行路径
进程:正在执行的应用程序
线程:进程的执行单元,执行路径
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径
多进程的意义?
提高CPU的使用率
多线程的意义?
提高应用程序的使用率
(2)Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
(3)多线程的实现方案(自己补齐步骤及代码 掌握)
A:继承Thread类
重写run方法
开启线程,并执行
调用线程:调用start()方法
B:实现Runnable接口
//创建被代理对象
Runnable my2 = new MyThread2();
//创建代理人
Thread t2 = new Thread(my2);
//调用执行方法主体
t2.start();// 真正执行的是run方法
两种方式的区别:
相同点:
都可以创建线程
执行的主体都是 run方法
启动线程都是start方法
区别:
Thread是类 Runnable是接口 Thread本身实现此接口
Java支持单继承,实现Runnable解决了单继承的问题
实现接口解决了数据共享的问题
C、使用Callable接口和Future创建线程(了解)
创建callable接口实现类,并实现call()方法,该call()方法将做线程的执行体,且该call()方法有返回值。
创建Callable实现类的实列,使用FutureTask类来包装Callable对象,该FutureTask对象封装该Callable对象的call()方法的返回值。
使用FutureTask对象作为Thread对象参数创建并启动线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
Daemon Thread(守护线程)
守护主要是为非守护线程(用户线程)服务,只要有一个非守护线程还在
执行,那么守护就不会结束,随着虚拟机的结束而结束
(4)线程的调度和优先级问题
A:线程的调度
a:分时调度
b:抢占式调度 (Java采用的是该调度方式)
B:获取和设置线程优先级
a:默认是5
b:范围是1-10
(5)线程的控制(常见方法)
static Thread | currentThread() 返回对当前正在执行的线程对象的引用。 |
A:休眠线程
static void | sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
void | interrupt() 中断线程。 |
B:加入线程
Thread(Runnable target) 分配新的 Thread 对象。 |
C:礼让线程
static void | yield() 暂停当前正在执行的线程对象,并执行其他线程 |
D:后台线程
void | join() 等待该线程终止 |
E:终止线程(掌握)
public static void main(String[] args) {
CountThread ct = new CountThread();
Thread t = new Thread(ct);
t.start();
// 线程执行一分钟求停止
for (int i = 0; i < 60; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 30) {
ct.setFlag(false);
}
System.out.println(i);
}
}
}
class CountThread implements Runnable {
private boolean flag = true;
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
while (flag) {
Date date = new Date();
System.out.println(sdf.format(date));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setFlag(boolean boo) {
this.flag = boo;
}
(6)线程的生命周期(参照 线程生命周期图解.bmp)
a、新建状态 使用new 出一个新的线程对象
b、就绪状态 调用start方法
c、运行状态 线程对象获取到cpu的时间片
d、阻塞状态 sleep、wait、join 线程进入阻塞状态
e、消亡 线程执行完了,结束了
(7)电影院卖票程序的实现
A:继承Thread类
B:实现Runnable接口
(8)电影院卖票程序出问题
A:为了更符合真实的场景,加入了休眠100毫秒。
B:卖票问题
a:同票多次
b:负数票
(9)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
线程的同步和死锁问题
synchronized:锁
一般在加锁:
a、把锁加到代码块中
锁对象(this),
如果不能锁对象,锁当前的字节码文件(类名.class)
b、把锁也可以加在方法上
Lock:
和synchronized一样,可以做线程同步
不同的是,需要手动获取和释放锁
lock() 枷锁
unlock() 释放锁
死锁问题:
如果同步代码多了,就容易产生死锁问题,
死锁问题,无法解决,只能尽量避免
多个线程操作多个资源时,每个线程都锁住一个资源,然后又必须获得
其资源啊,才能完成逻辑,这样造成程序无法执行,称作死锁
5、生产者消费者模式
wait、notify、notifyAll
6、任务调度
Timer : 定时器对象
TimerTask : 定时器的任务
线程:
程序、进程、线程 --***
创建线程的方式和区别
线程的状态
线程同步--四种方式
死锁
理解生产者和消费者模式
线程池的原理
单例模式
代理模式(静态)
(11)回顾以前的线程安全的类
A:StringBuffer
B:Vector
C:Hashtable
D:如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可。