Java多线程

Java多线程

 

进程:正在运行的程序或者是程序的一次执行过程,是动态的过程

线程:是程序中的一条执行路劲,也被称为轻量级进程

多线程:是指操作系统能同时执行多个线程

并行:多核CPU同时执行多个任务,例如 ,多个人同时做不同的事

并发:单核CPU同时执行多个任务,例如,多个人同时做同件事,秒杀系统

线程有五种状态

创建(准备)状态:当创建完Thread对象时(Thread  thread = new Thread() ),线程便进入了创建状态

就绪状态:当调用start()方法后便立即进入就绪状态,但不意味着立刻调度执行

运行状态:CPU调用,获得资源,就会进入运行状态,执行线程体里的代码块

阻塞状态:当调用sleep(),wait() 或同步锁定时,线程便进入阻塞状态,解除阻塞事件后便又进入就绪状态,等待CPU调度执行

死亡状态:线程中断或线程执行结束便进入死亡状态,就不能再执行,需要重新启动

每个线程都有一个优先级,这样有助于操作系统确定线程的调度顺序,Java线程优先级在Min_priority(1)到Max_priority(10)之间的范围内。默认优先级是norm_priority(5)

实现线程的方式有

1.继承Thread类:1.自定义线程类继承Thread类,2.重写run()方法编写线程执行体 3.创建线程对象,调用start()方法启动线程

使用继承Thread类的方式创建多线程时。编写简单,如果需要访问当前线程,则无需使用currentThread()方法,直接使用this关键字即可获得当前线程,

2.实现Runnable接口(优先选择): 1.自定义线程类实现Runnable接口,2.重写run()方法,编写线程执行体 3.创建线程对象,调用start()方法启动对象

a.避免单继承的局限性  b.Thread类也实现Runnable接口,实现该接口还可以继承其它类

3.实现Callable接口:1.自定义实现Callable接口,需要返回值类型,2.重写call()方法,需要抛出异常,3.创建目标对象

使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;

使用FutureTask对象作为Thread对象的target创建并启动新线程,调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

a.避免单继承的局限性  b.实现该接口还可以继承其它类

 

线程池:由于线程频繁的创建和销毁,会浪费大量资源,所以创建线程池可以节约资源

实现Runnable接口创建线程池

1.创建线程池对象

2.创建Runnable子类对象

3.提交Runnable子类对象

4.关闭线程池

实现Callable接口创建线程池

1.创建线程池对象

2.创建Callable接口子类对象

3.提交Callable接口子类对象

4.关闭线程池

 

多线程来的问题==>死锁

死锁产生的条件

1.请求和保持条件:一个线程因请求被占用资源而发生堵塞时,对已获得的资源保持不放

2.互斥条件:排斥性,当线程获得所分配的资源后,所分配的资源不能被其它线程占用

3.循环等待条件:发生死锁时,所等待的线程必定形成一个环路,死循环会造成永久阻塞。

4.不可剥夺条件:在一个线程未使用完已获得的资源之前,不能被其他线程强行剥夺,只有等待该线程使用完后并释放才能被其他线程获取。

如何避免死锁

1.破坏请求和保持条件:一次性申请所有的资源

2.破坏互斥条件:无法破坏,我们的锁本身就是用来让线程产生互斥

3.破坏循环等待条件:按照次序来申请资源

4.破坏不可剥夺条件:占有资源的线程可以尝试申请其它资源,如果申请不到,可以主动释放它占有的资源。

sleep()方法:使正在运行的线程处于(阻塞)睡眠状态,是属于Thread类一个静态方法,并且不考虑线程的优先级不会释放锁,会自动苏醒;

yield()方法:使线程处于就绪状态,

sleep()方法和yeild()方法的区别 没有声明任何异常,

wait()方法:使线程处于等待转台,并且会释放所持有对象的锁,是属于Object类的方法,不会自动苏醒,需要被唤醒;

notify()方法:可以唤醒一个处于等待状态的线程,又JVM决定唤醒哪个线程,与优先级无关;

notifyAll()方法:可唤醒所有处于等待状态的线程,并不是将对象的锁直接让给所有的线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态。

 

posted @ 2022-05-04 22:01  luoshen-luo  阅读(56)  评论(0编辑  收藏  举报