串行 和并行 :串行顾名思义就是 一串 ,有序的执行,类似道路的 单条通道,车子只能有序的一辆一辆行驶。
并行就类似于 多条通道的道路,有很多车可以同时并行出发行驶。
1多线程的概述:
进程:当前正在运行的程序,一个应用程序在内存中的执行区域(一块内存空间)。
线程:进程中的一个执行控制单元,执行路径(做的每一件事情可以看做一个线程)
一个进程可以有一个线程,也可以有多个线程(多线程)
单线程:安全性高,但效率低
多线程:安全性低,效率高(同时进行多个线程)如迅雷同时下载多个电影
2多线程(创建多个线程实例,并启动多个线程)的实现方式:
Thread类
写一个类继承Thread的子类,重写Thread的run方法(被测试类运行的方法),
测试类,创建线程实例:(和普通类一样new)子类名 变量名 = new 子类名();
启动线程:变量名.start();
String getName();获取线程的名字
Void setName(String name);修改线程的名字为name
多线程:cpu在执行顺序上不确定,在多个线程之间随机执行
3主方法是单线程的:
主方法在运行 的时候是单线程运行的
4多线程的实现方式:
Runnable接口
写一个子类实现Runnable接口,并重写public void run方法。
实现Runnable接口,不能直接用[getName 的静态方法]getName()方法;
必须先创建和获取线程Thread对象,用Thread对象调用getName方法。
//Static Thread currentThread() 返回当前线程对象:Thread t = Thread.currentThread();
T.getName();
测试类:创建线程实例:MyRunnable mr = new MyRunnable();
将子类创建的对象 传给Thread : Thread t = new Thread(mr);
//用 线程Thread对象调用getName方法。t.setName()
启动线程: t.start();
5多线程模拟火车站售票出现问题:
Static void sleep(long millis):让当前线程暂停一会,时间单位是毫秒
6分析火车站售票出现问题原因:
是因为不同的线程在进入if之后 Thread.Sleep方法让它休息一会,并没有卖出票,那下一个线程也会通过if判断,所以会出现-1 -2的情况
7使用同步代码块解决多线程案例中出现的问题:
问题出现的原因:1要有多个线程2要被多个线程所共享的数据3多个线程并发的访问共享的数据
同步:安全性高,效率低
不同步:效率高,但是安全性低
Synchronized:同步(修饰符),可以修饰代码块和方法,被修饰的带玫瑰和方法一旦被某个线程访问,则直接锁住,其他的线程将无法访问
同步代码块:
Synchronized(锁对象){
需要锁住运行的代码
}
注意:锁对象要被所有的线程锁共享。
8同步方法:
Synchronized :使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法全部被锁住,其他的线程无法再访问
Synchronized:注意
非静态同步方法的锁对象是this
静态的同步方法的锁对象是当前类的字节码对象(文件)
Get.class();获取字节码文件对象 或者类名.class();
9线程的声明周期:
生命周期:一个对象的从生到死的过程
新建 就绪 运行 死亡
创建线程对象 ——》具备了执行条件——》具备了执行条件——》线程对象变成了垃圾
没有具备执行权力 具备了执行权力
等待方法:等待wait();让当前的线程对象等待
唤醒notify();让等待的线程继续执行(是让线程回到就绪步骤)
继承thread 的方式:
代码:
public class test {
public static void main(String args[]) {
// 实例化继承thread 的类
myThread myThread = new myThread();
//
myThread.start();
// 执行
System.out.println("主线程执行位置1");
myThread.run();
System.out.println("主线程执行位置2");
myThread.run();
System.out.println("主线程执行位置3");
}
}
class myThread extends Thread {
// 一个内部类继承thread类
// 重写run方法 将需要并发执行的逻辑 写到run方法中
@Override
public void run() {
for (int i = 0; i < 9; i++) {
System.out.println("线程中的i值"+i);
}
}
}
运行结果:
一般开发过程中,涉及几十万的大量数据导入 会使用异步多线程,后台对参数校验完成后 即可启动多线程,然后返回给前台结果,并提示 ‘数据正在导入中’稍后查询等 信息。
也适用于 一些日志信息的就 适用异步线程,这样即使异步线程日志记录出现bug,也不影响主业务逻辑的正常执行。
start() 方法是完全异步的,run()方法在 主线程中 是有顺序的执行的。
下面写两个start() 和两个run() 方法 更能体现出来不同方法执行的顺序。
runnable 接口方式:
因为thread 类也是实现的 runnable 接口所以,下面截图 使用runnable方式启动线程后,调用start() 和run() 与 使用thread
类得到的结果 一样,start()方法是完全异步的,run()方法和主线程顺序是一致的。