【Java】多线程(五)高级知识

5. 多线程高级知识

5.1 多线程的七种状态

初始化状态

就绪状态

运行状态

死亡状态

阻塞状态

超时等待

等待状态

start():调用start()方法会使得该线程开始执行,正确启动线程的方式。

wait():调用wait()方法,进入等待状态,释放锁,让出CPU。需要在同步快中调用。

sleep():调用sleep()方法,进入超时等待,不释放锁,让出CPU

stop():调用sleep()方法,线程停止,线程不安全,不释放锁导致死锁,过时。

join():调用sleep()方法,线程是同步,它可以使得线程之间的并行执行变为串行执行。

yield():暂停当前正在执行的线程对象,并执行其他线程,让出CPU资源可能立刻获得资源执行。

yield()的目的是让相同优先级的线程之间能适当的轮转执行

notify():在锁池随机唤醒一个线程。需要在同步块中调用。

notifyAll():唤醒锁池里所有的线程。需要在同步块中调用。

在这里插入图片描述

Sleep 主动释放cpu执行权 休眠一段时间

运行状态→限时等待状态

限时等待状态→就绪状态→运行状态

Synchronized 没有获取到锁 当前线程变为阻塞状态
如果有线程释放了锁,唤醒正在阻塞没有获取到锁的线程
从新进入到获取锁的状态

wait() 运行—等待状态

notify() 等待状态–阻塞状态(没有获取到锁的线程 队列)

—就绪状态→运行状态

5.2 守护线程与用户线程

java中线程分为两种类型:用户线程和守护线程。

  • 通过Thread.setDaemon(false)设置为用户线程;
  • 通过Thread.setDaemon(true)设置为守护线程。
  • 如果不设置次属性,默认为用户线程。
  1. 守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。

  2. 用户线程是独立存在的,不会因为其他用户线程退出而退出。

5.3 多线程优先级

  1. 在java语言中,每个线程都有一个优先级,当线程调控器有机会选择新的线程时,线程的优先级越高越有可能先被选择执行,线程的优先级可以设置1-10,数字越大代表优先级越高

    注意:Oracle为Linux提供的java虚拟机中,线程的优先级将被忽略,即所有线程具有相同的优先级。所以,不要过度依赖优先级。

  2. 线程的优先级用数字来表示,默认范围是1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORTY.一个线程的默认优先级是5,即Thread.NORM_PRIORTY

  3. 如果cpu非常繁忙时,优先级越高的线程获得更多的时间片,但是cpu空闲时,设置优先级几乎没有任何作用。

//设置线程t1优先级为最低优先级——1
t1.setPriority(Thread.MIN_PRIORITY);
//设置线程t2优先级为最高优先级——10        
t2.setPriority(Thread.MAX_PRIORITY);

5.4 如何安全的停止线程

5.4.1 stop方法

stop:中止线程,并且清除监控器锁的信息,但是可能导致线程安全问题,标注已过时。

5.4.2 interrupt方法

Interrupt 打断正在运行或者正在阻塞的线程。

  1. 如果目标线程在调用Object class的wait()、wait(long)或wait(long, int)方法、join()、join(long, int)或sleep(long, int)方法时被阻塞,那么Interrupt会生效,该线程的中断状态将被清除,抛出InterruptedException异常。

  2. 如果目标线程是被I/O或者NIO中的Channel所阻塞,同样,I/O操作会被中断或者返回特殊异常值。达到终止线程的目的。

  3. 如果以上条件均不满足,比如目标线程正在运行,会设置此线程的中断状态:boolean值 isInterrupted() 为true,可以通过在run方法中进行判断自行处理线程中断位置

打断正在阻塞的线程
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
              e.printStackTrace();
        }
    }, "t1");
    t1.start();
    try {
        Thread.sleep(1000);
    } catch (Exception e) {

    }
    System.out.println("打断子线程");
    //调用interrupt 打断正在阻塞的线程
    t1.interrupt();
    System.out.println("获取打断标记:" + t1.isInterrupted());
}
打断正在运行的线程
public class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            // 如果终止了线程,则停止当前线程
            if (this.isInterrupted()) {
                break;
            }
        }
    }
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }
        myThread.interrupt();
    }
}
5.4.3 标志位法

增加一个判断,用来控制线程执行的中止

public class MyThread extends Thread {
    private volatile boolean isFlag = true;

    @Override
    public void run() {
        while (isFlag) {

        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.isFlag = false;
    }
}

5.5 Lock锁的基本使用

在jdk1.5后新增的ReentrantLock类同样可达到此效果,且在使用上比synchronized更加灵活

相关API:

  • 使用ReentrantLock实现同步

  • lock()方法:上锁

  • unlock()方法:释放锁

  • 使用Condition实现等待/通知 类似于 wait()和notify()及notifyAll()

Synchronized —属于JDK 关键字 底层属于 C++虚拟机底层实现 具有锁的升级过程:偏向锁,轻量级锁,重量级锁

Lock锁底层基于AQS实现-- 为重量级 使用过程中注意:获取锁、释放锁

ReentrantLock使用
public class MyThread implements Runnable {
    private Lock lock = new ReentrantLock();
    private int count = 100;
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                //获取锁
                lock.lock();
                if (count <= 0){
                    break;
                }
                count--;
                System.out.println(Thread.currentThread().getName()+" count: "+count);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"t1").start();
        new Thread(myThread,"t2").start();
    }
}
condition实现等待通知机制
public class MyThread {
    private Lock lock = new ReentrantLock();
    private Condition condition =lock.newCondition();
    
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.test();
    }
    
    public void test(){
        new Thread(()->{
            try {
                //获取锁
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "等待");
                //等待并释放锁
                condition.await();
                System.out.println(Thread.currentThread().getName() + "被唤醒");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }
        },"t1").start();
        try {
            Thread.sleep(3000);
            lock.lock();
            //3秒后唤醒等待线程
            condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值