多线程:
什么是进程:
进程是运行中的程序,通俗的来讲就是我们用电脑操作系统打开QQ这个程序,操作系统就会为我们为QQ这个进程分配地址内存。进程就是执行中的程序,它本身也有着产生,运行,消亡这几种状态
什么是线程:
线程就是进程的实例,一个进程有多个线程。
通俗的可以理解为:打开 QQ,可以同时打开多个聊天窗口,打开百度网盘可以同时下载多个任务
并发:
同一个时刻,多个任务交替执行,给人一种貌似同时的错觉,单核cpu实现的多任务就是并发
可以理解为似于:一个男人在开车的同时在打电话(当然这样是违法的)
并行:
同一时刻,多个任务同时执行,多核cpu可以实现并行
可以理解为:在同一时刻,一个男人在打电话,一个男人在开车
并发和并行也能同时存在:在同一时刻,一个男人一边打电话一边吃东西,一个男人在开车
创建线程的俩种方法:
1:继承Thread类 ,重写run方法
class Cat extends Thread{ int times = 0; @Override public void run() { //重写run方法,在这实现自己的业务逻辑 while (true) { System.out.println("我是小猫咪"+ times++); System.out.println("" +Thread.currentThread().getName()); try { //1000毫秒= 1秒 Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } if (times > 80) { break; } } cat.start() -->开启子线程 cat.run() --> 没有真正的启动线程,只是调用了run 方法 ,就会把run 方法执行完毕才向下执行 。 这样 主线程会堵塞 }
2:实现Runnable接口,重写run方法
3:实现Callable 接口,重写call 方法 (不常用)
Runnable 和 Thread 类的区别:
本质上没有区别,都要继承或者实现然后重写run 方法, 只不过Thread 类实现了 Runnable 接口。
实现Runnable 接口的方式,更加适合多个线程共享一个资源的情况,并且避免了Thread类的单继承的局限
建议使用Runnable接口
线程终止:
1:当线程完成以后,会自然退出
2:可以使用变量来控制run 方法 退出的方式停止线程,即通知方式
interrupt 中断线程,并没有真正的结束线程,一般用于中断正在的休眠线程
yield 让出的cpu,但不一定能够成功 (我就谦让一下,别当真啊。。。。。)
join 线程插队 (插队一定会成功!)。插队的线程一旦插队成功,就会执行完插入线程的所有的任务
线程的7种生命周期:
new 新建状态,
ready 准备状态, Running 运行状态 === Runnable 就绪状态 是否运行取决于调度器
Runnable 就绪状态 又分为ready 准备状态, Running 运行状态
ThreadWaiting 超时等待 join , sleep
Waiting 等待状态
Blocked 堵塞状态
Terminated 终止状态
Synchronized 关键字 -->是一种非公平锁
三个子线程同时去操作我们内存地址中的数据,线程1 抢到了锁之后,线程2和线程三就不能抢了,只能等待线程一执行完毕后释放锁,然后3个线程再去抢这把锁。注:(线程一还是可以再去抢到这把锁)所以说是非公平锁
只有拿到锁才能去执行,不然只能堵塞在这!!!
线程同步机制:在多线程编程种一些敏感数据不允许 被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性
也可以理解为:,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存进行操作,直到该线程完成操作,其它线程才能对该内存呢地址进行操作。
1:同步代码块
syschronized(对象){ //得到对象的锁,才能操作同步代码 //需要同步的代码 }
2:syschronized 还可以放在方法声明上,表示整个方法===为同步方法
public syschronized void m (String name){ //需要同步的代码 }
可以理解为:有一个去上厕所了,上厕所的时候将里面的门关上(上锁了),然后完事后在出来解锁,那么其它的小伙伴才能使用厕所
互斥锁
1:保证共享数据操作的完整性
2:每个对象都对应一个可称为“ 互斥锁” 的标记,这个标记用来保证在任意时刻,只能有一个线程访问该对象
3: 关键字synchronized 来与对象的互斥锁联系,当某个对象用synchronized 修饰时,表面该对象在任意时刻只能由一个线程访问。
4:同步会导致程序的执行效率变低!!!
5:同步方法(非静态的) 锁可以是this ,也可以是其他对象(要求是同一对象) Oject
6:同步方法(静态的) 的锁是当前类本身 类.class
public synchronized static void mi() { 锁是 当前类.class } public static void mi() { 锁是 当前类.class synchronized ( 当前类.class ){ //同步代码块 } }
线程死锁:
多个线程都占用了对方的锁资源,但还是都不肯想让,导致了死锁,在编程中一定要避免死锁的发生!
释放锁:
1:当前线程,同步代码块正常执行完成
2:当前线程,同步代码块种遇到break, return
3: 当前线程,同步代码块种出现未处理的Error 或者Exception 导致异常结束的
4:当前线程,同步代码块中执行了wait() 方法
不会释放锁:
1:当前线程,同步代码块中使用sleep(),yeild() 方法
2: 使用suspend() ,resume() 线程挂起 该方法不推荐