1 线程的生命周期以及状态转换
线程的生命周期包括五个阶段
1 新建状态:创建了一个新的线程对象
2 就绪状态:线程对象创建后,其他线程调用了该对象的start()方法,该状态的线程位于可运行线程池中,变得可运行,等待CPU的使用权
3 运行状态:就绪状态的线程获取了CPU的使用权,执行程序代码
4 阻塞状态:线程因为某种原因放弃了CPU的使用权,暂时停止运行,直到线程进入就绪状态,才有机会转到运行状态
阻塞的状态分为三种情况:
1.等待阻塞:运行的线程执行wait()方法,jvm会把该线程放入等待池里,wait会释放持有的锁
2.同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,jvm会把该线程放入锁池中
3.其他阻塞:运行的线程执行sleep方法或者join方法时或者发出了I/O请求,JVM会把该线程设置为阻塞状态
5 死亡状态:线程执行完或因为异常退出了run方法,该线程结束生命周期
线程的调度
1 线程的优先级
Java线程优先级用整数表示 1-10 数字越大优先级越高
Thread类提供了三个静态常量表示线程的优先级
static int MAX_PRIORITY ------10
static int MIN_PRIORITY ------1
static int NORM_PRIORITY -------5
线程的优先级不是固定不变的,可以通过setPriority(int newPriority)方法对它进行设置
thread.setPriority(Thread.MAX_PRIORITY);
thread.setPriority(5);
2 线程休眠
如果想人为控制线程的执行顺序,可以让正在执行的线程暂停,用sleep方法
代码演示
package com.jian;
public class Thread01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在输出i: "+ i);
if (i == 2) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
-------------------------
package com.jian;
public class Thread02 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在输出i: "+ i);
}
}
}
-------------------------
package com.jian;
public class Test {
public static void main(String[] args) {
Thread01 thread01 = new Thread01();
Thread02 thread02 = new Thread02();
thread01.start();
thread02.start();
}
}
输出
Thread-0正在输出i: 0
Thread-1正在输出i: 0
Thread-0正在输出i: 1
Thread-1正在输出i: 1
Thread-1正在输出i: 2
Thread-1正在输出i: 3
Thread-1正在输出i: 4
Thread-0正在输出i: 2
Thread-1正在输出i: 5
Thread-1正在输出i: 6
Thread-1正在输出i: 7
Thread-1正在输出i: 8
Thread-1正在输出i: 9
Thread-0正在输出i: 3
Thread-0正在输出i: 4
Thread-0正在输出i: 5
Thread-0正在输出i: 6
Thread-0正在输出i: 7
Thread-0正在输出i: 8
Thread-0正在输出i: 9
可以看到 Thread-0因为休眠了5秒,使用Thread-0 剩下的都在最后执行
3 线程让步
Thread.yield()方法,暂停当前正在执行的线程对象,把执行机会让给相同或者优先级更高的线程
因为Java虚拟机默认是抢占式调度模型,所有线程都会抢占CPU资源,所以在执行线程让步时,并不能保证立即执行其他线程
4 线程加入
join()方法 在某个线程中调用其他线程的join方法,则当前线程进入阻塞状态,直到另外一个线程执行完毕,这个线程才会继续执行
package com.jian;
public class Thread03 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 6; i++) {
System.out.println(Thread.currentThread().getName() + "输入: "+i);
}
}
}
class Example{
public static void main(String[] args) {
Thread t = new Thread(new Thread03(),"thread1");
t.start();
for (int i = 0; i < 6;i++) {
System.out.println(Thread.currentThread().getName() + "输入: "+i);
if (i == 2) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
输出
main输入: 0
thread1输入: 0
main输入: 1
thread1输入: 1
thread1输入: 2
thread1输入: 3
thread1输入: 4
thread1输入: 5
main输入: 2
main输入: 3
main输入: 4
main输入: 5
可以看到,调用了t的join方法,所以main线程等待t线程执行完才开始执行
5 多线程同步
同步代码块:
synchronized关键字
package com.Sale;
public class SaleThread implements Runnable{
private int ticket = 10;
Object lock = new Object();
@Override
public void run() {
while (true) {
synchronized (lock) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在发售第: " + ticket-- + "张票");
}
}
}
}
}
class Example1{
public static void main(String[] args) {
SaleThread saleThread = new SaleThread();
new Thread(saleThread,"售票窗口1").start();
new Thread(saleThread,"售票窗口2").start();
new Thread(saleThread,"售票窗口3").start();
new Thread(saleThread,"售票窗口4").start();
}
}
同步方法:
package com.Sale;
public class SaleThread01 implements Runnable{
private int ticket = 10;
Object lock = new Object();
private synchronized void saleTicket(){
if (ticket > 0 ) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在发售 "+ ticket--+"张票");
}
}
@Override
public void run() {
while (true) {
saleTicket();
}
}
}
class Example11{
public static void main(String[] args) {
SaleThread saleThread = new SaleThread();
new Thread(saleThread,"售票窗口1").start();
new Thread(saleThread,"售票窗口2").start();
new Thread(saleThread,"售票窗口3").start();
new Thread(saleThread,"售票窗口4").start();
}
}
6 同步锁
死锁演示
代码解释: A线程用着lock1 B线程用着lock2 A线程要结束还需要lock2锁 B线程要结束还需要lock1锁,但是由于A和B都无法释放自己占据的锁,所以程序死锁了
package com.deadlock;
/**
* 死锁演示
*/
public class Deadlock implements Runnable {
static Object lock1 = new Object();
static Object lock2 = new Object();
private Boolean flag;
Deadlock(Boolean flag){
this.flag = flag;
}
@Override
public void run() {
if(flag){
while (true) {
synchronized (lock1){
System.out.println(Thread.currentThread().getName() + "");
synchronized (lock2){
System.out.println(Thread.currentThread().getName() + "");
}
}
}
}else {
while (true) {
synchronized (lock2){
System.out.println(Thread.currentThread().getName() + "");
synchronized (lock1){
System.out.println(Thread.currentThread().getName() + "");
}
}
}
}
}
}
class Example{
public static void main(String[] args) {
Deadlock deadlock1 = new Deadlock(true);
Deadlock deadlock2 = new Deadlock(false);
new Thread(deadlock1,"A").start();
new Thread(deadlock2, "B").start();
}
}
多线程通信
案例 生产者消费者 生产顺序不一致问题
package com.conmunication;
import java.util.ArrayList;
import java.util.List;
/**
* 多线程通信案例,生产者,消费者
*/
public class Example{
public static void main(String[] args) {
List<Object>goods = new ArrayList<Object>();
long start = System.currentTimeMillis();
//创建一个生产者线程
Thread thread1 = new Thread(()->{
int num = 0;
while(System.currentTimeMillis()-start<=100){
goods.add("商品" + ++num);
System.out.println("生产产品" + num);
}
},"生产者");
//创建一个消费者线程
Thread thread2 = new Thread(()->{
int num = 0;
while (System.currentTimeMillis() - start <= 100) {
goods.remove("商品"+ ++num);
System.out.println("消费商品" +num);
}
},"消费者");
thread1.start();
thread2.start();
}
}
输出
生产产品1
消费商品1
生产产品2
消费商品2
生产产品3
生产产品4
生产产品5
生产产品6
消费商品3
并没有生产一个就消费一个,顺序乱掉了
为了解决上面的问题,需要用到线程通信,让线程知道自己什么时候该干什么事情
线程通信的常用方法
1 .void wait() :使当前线程放弃同步锁并进入等待,直到其他线程进入此同步锁,并调用notify()或者notifyAll()方法唤醒该线程为止
2:void notify():唤醒此同步锁上等待的第一个调用wait()方法的线程
3:void notifyALL() 唤醒此同步锁上调用wait()方法的全部线程
使用线程通信方法优化生产者消费者程序
package com.conmunication;
import java.util.ArrayList;
import java.util.List;
/**
* 多线程通信案例,生产者,消费者
*/
public class Example02{
public static void main(String[] args) {
List<Object>goods = new ArrayList<Object>();
long start = System.currentTimeMillis();
//创建一个生产者线程
Thread thread1 = new Thread(()->{
int num = 0;
while(System.currentTimeMillis()-start<=100){
//同步代码块
synchronized (goods){
//如果goods里面的商品大于0,让生产者线程暂时等待
//等待消费者线程把商品消费到0,然后继续执行生产者
if(goods.size()>0){
try {
goods.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
goods.add("商品" + ++num);
System.out.println("生产商品"+num);
}
}
}
},"生产者");
//创建一个消费者线程
Thread thread2 = new Thread(()->{
int num = 0;
while (System.currentTimeMillis() - start <= 100) {
synchronized (goods) {
//如果good里面的商品等于0,就暂停消费者线程,让生产者线程进行生产
//当商品大于0时,再启动消费者线程,消费商品
if (goods.size() <= 0) {
goods.notify();
}else{
goods.remove("商品"+ ++num);
System.out.println("消费商品" +num);
}
}
}
},"消费者");
thread1.start();
thread2.start();
}
}
输出正常
生产商品1
消费商品1
生产商品2
消费商品2
生产商品3
消费商品3
生产商品4
消费商品4
生产商品5
消费商品5
生产商品6
消费商品6
生产商品7
消费商品7
生产商品8
消费商品8
生产商品9
消费商品9
生产商品10
消费商品10
生产商品11
消费商品11
生产商品12
消费商品12
生产商品13
消费商品13