目录
1.进程与线程
进程是 OS(操作系统operating system,简称OS)分配资源的基本单位,线程是执行调度的基本单位。可能有些拗口,这样理解:
多进程是指操作系统能同时运行多个任务(程序)
这就是4个进程
多线程是指在同一程序中有多个顺序流在执行
例如播放电影可以看见图像的同时还可以听见声音,图像与声音就是两个线程,感觉不到它们之间的时差,是因为CPU执行顺序太快了,人感受不到
微信在电脑运行时的线程内存简述图
Java程序启动至少会有两个线程启动
- 每当使用Java命令执行一个类时,实际上都会启动一个JVM,每个JVM实际上就是在操作系统中启动一个进程
- Java本身具备了垃圾回收机制,所以每个Java运行时至少会启动两个线程,一个main线程,一个是GC(垃圾回收机制)
2.创建Java线程三种方式
run()与start()区别
- 调用start方法方可启动线程,真正实现了多线程
- 而run方法只是thread的一个普通方法调用还是在当前线程里执行,并没有增加线程的数量
第一种:继承Thread类
第二种:实现Runnable接口
两种方式区别
- 继承Thread类
- 子类继承Thread类具备多线程的能力
- 启动线程:子类对象.statr();
- 不建议使用:避免OOP单继承局限性
- 实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象+Thread对象.start();
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
练习项目
购买火车票,耳熟能详的多线程入手项目了,通过购买火车票项目来查看线程在CPU之间的频繁调度
public class BuyTrainTickets implements Runnable{
int ticketNum = 10;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (ticketNum > 0) {
// Thread.currentThread().getName() 获取当前线程的名字
System.out.println("我在" + Thread.currentThread().getName() + "买到了第" + ticketNum-- + "张车票");
}
}
}
// Main方法:
public static void main(String[] args) {
BuyTrainTickets buyTrainTickets = new BuyTrainTickets();
// new Thread(buyTrainTickets, "窗口1").start(); --->Thread t1 = new Thread(buyTrainTickets, "窗口1"); t1.start();
new Thread(buyTrainTickets, "黄牛那里").start();
new Thread(buyTrainTickets, "火车站那里").start();
new Thread(buyTrainTickets, "网上").start();
}
}
运行结果:
暴露问题:多个线程共享同一个资源的时候线程不安全,数据紊乱
多运行几次,会发现结果都不一样
第三种:实现Callable接口(了解)
对比第一种和第二种创建线程的方式发现,无论第一种继承Thread类的方式还是第二种实现Runnable接口的方式,都需要有一个run方法,但是这个run方法有不足:
- 不能抛出异常
- 没有返回值
基于上面的两个不足,在JDK1.5以后出现了第三种创建线程的方式:实现Callable接口,实现Callable接口好处:
- 有返回值
- 能抛出异常
缺点:线程创建比较麻烦