Java学习第六天----线程的阻塞、礼让、休眠、守护等以及Lamda表达式的运用

Lamda表达式

  • λ:希腊字母表中排序11位的字母(Lamda);

  • 作用:避免匿名内部类定义过多;

  • 函数式编程的逻辑

    1)(params)-> expression[表达式]

    2)(params)-> statement[语句]

    3)(params)-> {statements}

    new Thread(()->System.out.println("Lamda表达式")).start();
  • 理解Function Interface(函数式接口)是学习Java8 Lamda的关键所在

    函数式接口定义:

    • 任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口;

    • 对于函数式接口,我们可以通过Lamda表达式来创建该接口的对象

// 函数式接口----推导Lamda表达式
public class FunctionInterface {
    public static void main(String[] args) {
​
        // 7 lamda表达式
        Test test = (String name)->{
            System.out.println(name + " love fly!");
        };
        test.love("wa");
​
        // 8 简化一:参数类型
        test = (name)->{
            System.out.println(name + " love fly!");
        };
        test.love("wa");
​
        // 9 简化二:简化括号
        test = name->{
            System.out.println(name + " love fly!");
        };
​
        test.love("wa");
​
        // 10 简化三:去掉花括号
        test = name->System.out.println(name + " love fly!");
​
        // 总结:
               // lamda表达式只能有一行代码的情况下才能简化为一行,如果有多行,需要用代码块包裹
               // 前提是接口必须为函数式接口
               // 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
        test.love("wa");
​
        TestLamda lamda = new Lamda();
        lamda.lamda();
​
        lamda = new Lamda2();
        lamda.lamda();
​
​
​
        // 4局部内部类
        class Lamda3 implements TestLamda {
​
            @Override
            public void lamda() {
                System.out.println("Java 博大精深!开发前辈-佩服之至33333!");
            }
        }
​
        lamda = new Lamda3();
        lamda.lamda();
​
        // 5匿名内部类,没有类的名称,必须借助接口或者父类
        lamda = new TestLamda(){
            @Override
            public void lamda() {
                System.out.println("Java 博大精深!开发前辈-佩服之至44444!");
            }
        };
        lamda.lamda();
​
        // 6lamda简化
        lamda = ()->{
            System.out.println("Java 博大精深!开发前辈-佩服之至55555!");
        };
        lamda.lamda();
    }
​
    // 3静态内部类
    static class Lamda2 implements TestLamda {
​
        @Override
        public void lamda() {
            System.out.println("Java 博大精深!开发前辈-佩服之至22222!");
        }
    }
}
​
// 1定义一个函数式接口
interface TestLamda {
    void lamda();
}
​
// 2实现类
class Lamda implements TestLamda {
​
    @Override
    public void lamda() {
        System.out.println("Java 博大精深!开发前辈-佩服之至!");
    }
}
​
interface Test{
    void love(String name);
}
​

线程停止

  1. 线程五大状态:

    • 创建状态:Thread t = new Thread()----------线程对象创建就进入到新生状态

    • 就绪状态:当调用start()方法,线程进入就绪状态

    • 阻塞状态:调用sleep、wait或者同步锁定时,线程进入阻塞状态,代码不会往下执行线程,阻塞接触后,重新进入就绪状态,等待CPU调度执行

    • 运行状态:线程开始执行线程体的代码块

    • 死亡状态:线程中断或结束,就会进入死亡状态,不能再次启动

 

 

  • 不推荐使用JDK提供的stop()、destroy()方法【已废弃】

  • 推荐使用标志位去让线程自动停止

    ​
    // 1,通过标志位停止线程
    // 2,建议设置次数,尽量避免死循环
    // 3,不要使用stop,destroy等过时的方法(有bug或者弊端)
    public class StopThread implements Runnable{
        // 1,定义线程体使用的标识
        private boolean judge = true;
    ​
        @Override
        public void run() {
            // 2,线程体使用该方法
            int i= 0;
            while (judge){
                System.out.println("线程正在执行中!"+i++);
            }
        }
    ​
        // 3,对外提供方法改变标识
        private void stop(){
            this.judge=false;
        }
    ​
        public static void main(String[] args) {
            StopThread stopThread = new StopThread();
            new Thread(stopThread).start();
            for (int i = 0 ; i < 100 ; i++){
                System.out.println("Main!"+i);
                if (i == 89){
                    stopThread.stop();
                    System.out.println("线程停止!");
                }
            }
        }
    }

线程休眠

  • sleep(时间):指定当前线程阻塞的毫秒数 1000毫秒 = 1秒

  • 异常:InterruptedException

  • sleep时间到达后线程进入就绪状态

  • sleep可以模拟网络延时,倒计时

  • 每一个对象都已一个锁,sleep不会释放锁

  • 模拟网络延时:

    // 线程休眠----模拟网络延时,放到问题的发生性
    public class SleepThread implements Runnable{
        private Integer number = 10;
        @Override
        public void run() {
            while (true){
                if (number<=0){
                    break;
                }
                // 模拟网络延时
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"--》拿到了第"+number--+"票!");
            }
        }
    ​
        public static void main(String[] args) {
            SleepThread sleepThread = new SleepThread();
            // 线程不安全
            new Thread(sleepThread,"小明").start();
            new Thread(sleepThread,"小军").start();
            new Thread(sleepThread,"小杨").start();
        }
    }
  • 模拟倒计时----以及获取当前时:分:秒:

    import java.text.SimpleDateFormat;
    import java.util.Date;
    ​
    // 模拟倒计时
    public class SleepThread2 implements Runnable{
        private Integer time = 30;
        @Override
        public void run() {
            Date nowTime = new Date(System.currentTimeMillis());// 获取当前时间
            while (true){
                if(time<0)
                {
                    break;
                }else{
                    try {
                        Thread.sleep(1000);
                        System.out.println(new SimpleDateFormat("HH:mm:ss").format(nowTime));
                        nowTime = new Date(System.currentTimeMillis());// 获取当前时间
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(time--);
            }
        }
    ​
        public static void main(String[] args) {
            SleepThread2 sleepThread2 = new SleepThread2();
            new Thread(sleepThread2).start();
        }
    }

线程礼让(yield)

  • 礼让线程,让当前正在执行的线程展厅,但不阻塞

  • 将线程从运行状态转为就绪状态

  • 让CPU重新调度,但不一定成功!得看CPU如何处理

    // 线程礼让
    // 礼让不一定成功,看CPU心情
    public class YieldThread {
        public static void main(String[] args) {
            MyYield myYield = new MyYield();
            new Thread(myYield,"threadOne").start();
            new Thread(myYield,"threadTwo").start();
    ​
    ​
        }
    }
    ​
    class MyYield implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"线程开始执行!");
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+"线程停止执行!");
        }
    }
  • 礼让不成功:

 

  • 礼让成功:

 

线程强制执行(Join)

  • Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

  • 可以想象成插队

    // 线程强制执行----Join
    public class JoinThread implements Runnable{
        @Override
        public void run() {
            for(int i = 0 ; i< 100 ; i++ ){
                System.out.println("Vip线程!"+i);
            }
        }
    ​
        public static void main(String[] args) throws InterruptedException {
            JoinThread joinThread = new JoinThread();
            Thread thread = new Thread(joinThread);
            thread.start();
            for(int i = 0 ; i < 100 ; i++){
                if(i == 50){
                    thread.join();  // 类似于插队,让thread线程先全部跑完,再接着跑其他线程
                }
                System.out.println("Main"+i);
            }
        }
    }

线程状态观测

  • new 尚未启动的线程处于此状态

  • runnable 在Java虚拟机中执行的线程出于此状态

  • blocked 被阻塞等待监视器锁定的线程出于此状态

  • waiting 正在等待另一个线程执行特定动作的线程处于此状态

  • time_waiting 正在等待另一个线程执行动作到达指定等待时间的线程处于此状态

  • terminated 已退出的线程处于此状态

    // 观察线程状态
    public class ObservationThread {
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(()->{
                for (int i = 0  ; i < 5 ; i++){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("=======================");
            });
    ​
            // 观察状态
            // new
            Thread.State state = thread.getState();
            System.out.println(state);
    ​
            // runnale
            thread.start();
            state = thread.getState();
            System.out.println(state);
    ​
            // 线程不终止,就一直输出状态
            while (state != Thread.State.TERMINATED){
                Thread.sleep(100);
                state = thread.getState();
                System.out.println(state);
            }
            
            // 停止之后再尝试运行,会报错
            thread.start();
        }
    }

     

     

线程优先级(Priority)

  • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行

  • 线程的优先级用数字标识,范围从1~10

    • Thread.MIN_PRIORITY = 1;

    • Thread.MAX_PRIORITY = 10;

    • Thread.NORM_PRIORITY = 5;

  • 设置了线程优先级只是让该线程有更大的可能被CPU先调度,并不是指优先级高的就一定先执行(性能倒置),且一般线程的优先级在start()调度前设置

  • 使用一下方式改变或获取优先级

    • getPriority()

    • setPriority()

import javafx.scene.layout.Priority;

// 线程优先级
public class PriorityThread extends Thread{
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+"-》"+Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();
        Thread thread1 = new Thread(myPriority);
        Thread thread2 = new Thread(myPriority);
        Thread thread3 = new Thread(myPriority);
        Thread thread4 = new Thread(myPriority);
        Thread thread5 = new Thread(myPriority);
        thread1.setPriority(1);
        thread2.setPriority(3);
        thread3.setPriority(5);
        thread4.setPriority(7);
        thread5.setPriority(10);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();




    }
}

class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-》"+Thread.currentThread().getPriority());
    }
}

 

守护(Daemon)线程

  • 线程分为用户线程和守护线程

  • 虚拟机必须确保用户线程执行完毕

  • 虚拟机不用等待守护线程执行完毕(后台记录操作日志、监控内存、垃圾回收)

// 守护线程
public class DaemonThread {
    public static void main(String[] args) {
        God god = new God();
        Me me = new Me();

        Thread thread = new Thread(god);
        thread.setDaemon(true);// 默认是false,表示是用户线程,正常的线程
        thread.start();// 启动守护线程
        new Thread(me).start();
    }

}

// 上帝
class God implements Runnable{

    @Override
    public void run() {
        while (true){
            System.out.println("上帝保佑着你");
        }
    }
}


// 你
class Me implements Runnable{

    @Override
    public void run() {
        for (int i = 0 ; i< 36500 ;i++){
            System.out.println("你开心的活了一生!"+i);
        }
        System.out.println("GoodBye!The World!");
    }
}
  • 守护线程会随着用户线程结束而跑一会儿再结束

线程同步机制(***重要)

  • 并发:同一个对象被多个线程同时操作--》即多个线程操作同一个资源

  • 为了解决并发问题,我们需要用到线程同步:线程同步实际上是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池,形成队列,等待前面线程使用完毕,下一个线程再使用;

  • 线程同步条件:队列+锁 ----》解决线程安全

  • 线程同步的实现及问题:

    1. 实现:在访问时,加入锁机制-->synchronized,当一个线程获得对象的排它锁,会独占资源,其他线程必须等待,使用后释放锁即可;

    2. 问题一:一个线程持有锁会导致其他所有需要此锁的线程挂起;

    3. 问题二:在多线程的竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;

    4. 问题三:如果一个优先级高的线程等待一个一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值