首先,我们需要了解一些基本知识:
微观概念:
并行: 指两个或多个事件在同一时刻点发生
并发: 指两个或多个事件在同一时间段内发生
一、进程(Process)与线程(thread)
进程:运行的应用程序和所占用的资源,是指一个内存中运行的应用程序。
每个进程都有自己独立的一个内存空间(数据交互困难),
一个应用程序可以同时启动多个进程。比如同时听音乐和看小说
线程:进程中单个任务执行流,是指进程中的一个执行任务(控制单元),一个进程可以同时并发运行多个线程
多任务系统,该系统可以运行多个进程,一个进程可以 执行多个任务,一个进程包含多个线程
多线程:一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行任务,即多线程
简单点:在操作系统中允许多个任务,每一个任务就是一个进程,每一个进程也可以执行多个任务,
每个任务就是一个线程,任务之间依靠线程进行通信
注意:因为一个进程中的多线程是并发进行的,那么从微观角度上来考虑也是有先后顺序的,那么哪个线程
先执行完全取决于CPU调度器(java线程一般取决于JVM),程序员控制不了
二、多线程的优势
1.进程之间不能共享内存,而线程之间共享内存(堆内存)
2.系统创建进程时需要为该进程重新分配系统资源,创建线程则代价小很多,因此实现多任务并发时,多线程效率更高
3.Java语言本身内置多线程功能的支持,而不是单纯作为底层系统的调度方式,从而简化了多线程编程
4.多线程下载(网络带宽) 即一个线程就是一个文件的下载通道,多线程就是同时开启了多个下载通道
bit位 byte字节 1024kb/s -> 1024/8 128
比如 单行道与多行道 LOL CS
三、创建和启动线程 【重点】
方式一:继承Thread类
步骤:1.定义一个类继承Thread类
2.在该类中覆盖Thread类中的run方法
3.在run方法中实现需要执行的操作(注明线程执行体)
4.在main方法(线程)中,创建线程对象,并调用start()方法启动线程
A类 a = new A类();
a.start();
eg:
package com.javaweb.practice; public class MyThread extends Thread{ public MyThread(String name){ super(name); } public void run(){ for(int i=0 ; i<10 ; i++){ System.out.println(getName()+":正在执行!"+i); } } }
package com.javaweb.practice; import java.util.Date; public class Test extends Date { public static void main(String[] args) { MyThread mt = new MyThread("新的线程"); mt.start(); for (int i = 0; i < 10; i++) { System.out.println("main线程!"+i); } } }
结果:
main线程!0 main线程!1 main线程!2 main线程!3 main线程!4 main线程!5 main线程!6 main线程!7 新的线程:正在执行!0 新的线程:正在执行!1 新的线程:正在执行!2 新的线程:正在执行!3 新的线程:正在执行!4 新的线程:正在执行!5 新的线程:正在执行!6 新的线程:正在执行!7 新的线程:正在执行!8 新的线程:正在执行!9 main线程!8 main线程!9
注意:千万不要使用对象调用run方法,如果调用run方法,等于就是只启动了一个线程,未开启别的线程
方法:getName(): 拿到当前线程的名称setName(String name): 给当前线程的名字赋值
currentThread() 返回对当前正在执行的线程对象的引用。
sleep() 当前线程睡眠,让其他线程抢CPU资源
方式二:实现Runnable接口
步骤:1.定义一个类A实现Runable接口,注意A类不是线程类
2.在A类中覆盖Runable接口中的run方法
3.在run方法中实现需要执行的操作(注明线程执行体)
4.在main方法(线程)中,创建线程对象,并调用start()方法启动线程
Thread t = new Thread(new A());
t.start();
eg:
package com.javaweb.practice; import java.util.Currency; public class MyRunnable implements Runnable { public void run() { for(int i=0 ; i<10 ; i++){ System.out.println("线程"+i); } } }
package com.javaweb.practice; public class Test { public static void main(String[] args) { //创建线程执行目标类对象 MyRunnable runn = new MyRunnable(); //将Runnable接口的子类对象作为参数传递给Thread类的构造函数 Thread thread01 = new Thread(runn,"线程1"); Thread thread02 = new Thread(runn,"线程2"); //开启线程 thread01.start(); thread02.start(); for (int i = 0; i < 10; i++) { System.out.println("main线程!"+i); } } }
四 继承方式与实现方式的区别:
继承方式:
1.java中类是单继承的,如果继承了Thread,该类就不能再有其他直接父类了
2.从操作上来分析,继承方式更简单,获取线程的名称也简单
3.从多线程共享同一个资源上分析,继承方式不能做到
实现方式推荐使用:
1.java中的类可以实现多个接口,此类还可以继承其他的类
2.操作上实现方式稍微复杂点,获取名称只能通过Thread.currentThread().getName()来拿
3.从多线程共享一个资源上,实现方式才能做到是否共享同一个资源
推荐使用 实现方式
五、线程的生命周期
1. 新建 : new thread实例对象
2. 就绪 : 调用start() 启动线程进入就绪
3. 运行 :运行run方法里面的代码
4. 中断(阻塞):正在运行的线程由于外部原因引起当前线程中断或阻塞,等到引起阻塞原因消失,回到就绪状态
5.死亡 : 中断线程