2.线程实现(重点)

线程的创建

三种创建方式

在这里插入图片描述

继承Thread类

继承Thread类实现多线程步骤如下:

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

创建线程方式1:继承Thread(通过查看源码发现Thread 是实现Runnable接口的)
注意:线程开启不一定立即执行,由CPU调度安排。

package com.y.demo01;

//创建线程方式一: 继承 Thread类, 重写run()方法, 调用start()开始线程

//总结:注意,线程开启不一定立即执行, 有CPU调度执行

public class TestThread1  extends Thread{

    @Override
    public void run() {
//        run()方法 线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在撸代码" + i);
        }
    }

    public static void main(String[] args) {
        // main线程,主线程

        TestThread1 thread1 = new TestThread1();
        thread1.start();

        for (int i = 0; i < 60; i++) {
            System.out.println("我在学习"+ i);

        }
    }
}

案例:网图下载

package com.y.demo01;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习 Thread, 实现多线程同步下载图片
public class TestThread2 extends Thread{

    private String url;
    private String name;

    public  TestThread2(String url,String name){
        this.url = url;
        this.name = name;
    }

    //线程的执行体
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }

    public static void main(String[] args) {
        TestThread2 testThread21 = new TestThread2("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","1.jpg");
        TestThread2 testThread22 = new TestThread2("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","2.jpg");
        TestThread2 testThread23 = new TestThread2("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","3.jpg");

        testThread21.start();
        testThread22.start();
        testThread23.start();
    }
}

//下载器
class WebDownloader {
    //下载方法
    public void downloader(String url, String name){ //下载器
        try {
            //文件单元.复制URL文件
            // 把一个url变成一个文件
            FileUtils.copyURLToFile( new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

实现Runnable接口

  1. 定义MyRunnable类实现Runnable接口

  2. 实现**run()**方法,编写线程执行体

  3. 创建线程对象,调用**start()**方法启动线程

package com.y.demo01;


//创建线程方式2:实现 Runnable 接口, 重写run方法, 执行线程需要丢入 Runnable 接口实现类, 调用start方法
public class TestThread3 implements Runnable{
    @Override
    public void run() {
//        run()方法 线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在撸代码" + i);
        }
    }

    public static void main(String[] args) {
        // main线程,主线程
        TestThread3 thread3 = new TestThread3();
//        Thread thread = new Thread(thread3);
//        thread.start();
        //简写
        new Thread(thread3).start();

        for (int i = 0; i < 60; i++) {
            System.out.println("我在学习"+ i);

        }
    }

}

Thread 和Runnable小结

继承Thread类
  1.子类继承Thread 类具有多线程能力
  2.启动线程:子类对象.start()
  3.不建议使用:避免OOP单继承局限性

实现Runnable 接口
  1.实现接口Runnable 具有多线程能力
  2.启动线程:传入目标对象+Thread对象.start()
  3.推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

创建线程方式3:

实现Callable 接口

  1. 实现Callable接口,需要返回值类型

  2. 重写call 方法,需要抛出异常

  3. 创建目标对象

  4. 创建执行服务:

  5. 提交执行:

  6. 获取结果:

  7. 关闭服务:

    package com.y.demo02;
    
    import com.y.demo01.TestThread2;
    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.concurrent.*;
    
    //线程创建方式三:实现 callable 接口
    /*
    
     */
    public class TestCallable implements Callable<Boolean> {
    
        private String url;
        private String name;
    
        public  TestCallable(String url,String name){
            this.url = url;
            this.name = name;
        }
    
        //线程的执行体
    
        public Boolean call() {
            WebDownloader webDownloader = new WebDownloader();
            webDownloader.downloader(url,name);
            System.out.println("下载了文件名为:"+name);
            return true;
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            TestCallable t1 = new TestCallable("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","1.jpg");
            TestCallable t2 = new TestCallable("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","2.jpg");
            TestCallable t3 = new TestCallable("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","3.jpg");
    
            //创建执行服务:  需要创建一个池子
            ExecutorService ser = Executors.newFixedThreadPool(3);
            //提交执行:
            Future<Boolean> r1 = ser.submit(t1);
            Future<Boolean> r2 = ser.submit(t2);
            Future<Boolean> r3 = ser.submit(t3);
            //获取结果
            Boolean rs1 = r1.get();
            Boolean rs2 = r2.get();
            Boolean rs3 = r3.get();
            //关闭服务
            ser.shutdown();
        }
    
    }
    
    
    //下载器
    class WebDownloader {
        //下载方法
        public void downloader(String url, String name){ //下载器
            try {
                //文件单元.复制URL文件
                // 把一个url变成一个文件
                FileUtils.copyURLToFile( new URL(url), new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downloader方法出现问题");
            }
        }
    }
    
    下载了文件名为:2.jpg
    下载了文件名为:1.jpg
    下载了文件名为:3.jpg
    

    多个线程同时操作一个对象,如:取钱、买火车票

    初识并发问题

    package com.y.demo01;
    
    //多个线程同时操作同一个对象
    //买火车票
    
    //发现问题: 多个线程操作同一个资源的情况下, 线程不安全, 数据紊乱
    public class TestThread4 implements Runnable{
    
        //票数 ticketNums 票券
        private int ticketNums = 10;//ticketNums 票券
    
        @Override
        public void run() {
            while (true) {
    
                if (ticketNums <= 0) {
                    break;
                }
                try {
                    //模拟 延迟
                    Thread.sleep(200); //毫秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                // Thread.currentThread().getName():获得当前执行线程的名字
                System.out.println(Thread.currentThread().getName() + " -->拿到了第"+ ticketNums-- +"票");
    
            }
        }
    
        public static void main(String[] args) {
    
            TestThread4 ticket = new TestThread4(); // 票
    
            //线程 线程名
            Thread thread = new Thread(ticket,"黄牛党");
            thread.start();
            // 简化
            new Thread(ticket,"小明").start();
            new Thread(ticket,"老师").start();
    
    
        }
    }
    小明 -->拿到了第10票
    黄牛党 -->拿到了第10票
    老师 -->拿到了第9票
    小明 -->拿到了第8票
    黄牛党 -->拿到了第6票
    老师 -->拿到了第7票
    老师 -->拿到了第5票
    黄牛党 -->拿到了第5票
    小明 -->拿到了第5票
    老师 -->拿到了第4票
    黄牛党 -->拿到了第4票
    小明 -->拿到了第4票
    小明 -->拿到了第2票
    黄牛党 -->拿到了第1票
    老师 -->拿到了第3

    案例:龟兔赛跑

    1.首先来个赛道距离,然后要离终点越来越近 , for循环判断了100步

    2.判断比赛是否结束 ,gameOver() 方法

    3.打印出胜利者

    4.龟兔赛跑开始

    5.故事中是乌龟赢了,兔子需要睡觉,所以我们模拟兔子睡觉

    6.终于,乌龟赢了

package com.y.demo01;

//Race:比赛

// 模拟 龟兔赛跑
public class Race implements Runnable{

    //胜利者
    private static String winner; //赢家

    @Override
    public void run() {

        for (int i = 0; i <= 100; i++) {

            //模拟兔子睡觉
            if ( Thread.currentThread().getName().equals("兔子") && i % 20 == 0) {

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //判断比赛是否结束
            boolean flag = gameOver(i);

            //如果比赛结束了,停止程序
            if (flag){ // 默认为 true
                break;
            }
                                //线程的名字
            System.out.println(Thread.currentThread().getName()+ "跑了" +i+ "步");
        }
    }

    //判断是否完成比赛
    private  boolean gameOver (int steps){ //游戏结束
        //判断是否有胜利者
        if (winner != null){ // 已经存在胜利者了
            return true;
        }
        else if (steps >= 100) {
            winner = Thread.currentThread().getName();//线程名字 赋值给 winner
            System.out.println("winner is" + winner);
            return true;
        }

        return false;

    }

    public static void main(String[] args) {

        Race race = new Race();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

静态代理

在这里插入图片描述

静态代理总结:

1. 真实对象和代理对象都要实现同一个接口

2. 代理对象 要代理 真实角色

好处:

代理对象 可以做很多对象做不了的事情

真实对象 专注做自己的事情

package com.y.staticProxy;

//静态代理

/*
静态代理模式总结
真实对象或目标对象 和 代理对象都要实现同一个接口
代理对象要 代理 真实角色
*/
/*
好处:
    代理对象 可以做很多 真实对象 做不了的事情
    真实对象 专注做自己的事情
 */
public class StaticProxy {

    public static void main(String[] args) {

        You you = new You();// 你要结婚

        //多线程开启
        Thread thread = new Thread( );
        thread.start();
            //简化
        new Thread().start();

         //Runnable:接口  Thread类也实现了Runnable接口
        new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();
        //lambda 表达式简化
        new Thread( () -> System.out.println("ai")).start();
        new Thread( ()-> System.out.println("我爱你") ).start();


        /*WeddingCompany weddingCompany = new WeddingCompany( you );
        weddingCompany.HappyMarry();*/
        //简化
        new WeddingCompany( new You()).HappyMarry();


    }

}

//共同接口  结婚
interface Marry{
    //人间四大喜事
        //久旱逢甘露
        //他乡遇故知
        //洞房花烛夜
        //金榜题名时

    void HappyMarry();

}

// 你 真实角色
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("结婚了,超开心");
    }
}

//婚庆公司 代理角色,帮助你结婚
class WeddingCompany implements Marry{

    //目标对象 结婚
//  真实对象是代理来的  代理谁 --->真实目标角色
    private Marry target;

    //构造方法:传递参数
    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {

        before();
        this.target.HappyMarry(); //这就是:真实对象 ,调用了一个结婚
        after();
    }


    //结婚之前
    private void before() {
        System.out.println("结婚之前,布置现场");
    }

    //结婚之后
    private void after() {
        System.out.println("结婚之后,收尾款");
    }


}


Lambda表达式

入 希腊字母表中排序第十一位的字母,英语名称为Lambda

避免内部类定义过多

其实质属于函数式编程概念

(params) -> expression  [表达式]
(params) -> statement [语句]
(params) -> {statement }
123
new Thread(()-> System.out.println("多线程学习")).start();
1

为什么要使用lambda 表达式

1.避免你们内部类定义过多

2.可以让你的代码看起来很简洁

3.去掉了一堆没有意义的代码,只留下核心的逻辑

函数式接口

  • 理解Functional lnterface(函数式接口)是学习Java8 lambda表达式的关键所在。

  • 函数式接口的定义

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

2.对于函数式接口,我们可以通过lambda 表达式来创建该接口的对象。

public interface Runnable{ //多线程接口
    public abstract void run();//抽象方法
}

代码实现

package com.y.lambda;

/*
推到 lambda表达式

 */
public class TestLambda1 {

    //3.静态内部类 (把 实现类 放在 静态内部类里边)
    //实现类
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }


    public static void main(String[] args) {
        //创建一个接口对象
        ILike like = new Like();
        like.lambda();

         like = new Like2();
         like.lambda();

         //4.局部内部类 (方法里边)
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("I like lambda3");
            }
        }
        like = new Like3();
        like.lambda();

        //5.匿名内部类 , 没有类的名称,必须借助 接口 或者 父类  重写它的方法
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("I like lambda4");

            }
        };
        like.lambda();

        //6.用 lambda简化
        like = ()-> {
            System.out.println("I like lambda5");
        };
        like.lambda();

    }


}

//1.定义一个函数式接口 (只有一个方法的接口就是函数式接口)
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}
I like lambda
I like lambda2
I like lambda3
I like lambda4
I like lambda5

简化

package com.y.lambda;

public class TestLambda2 {



    public static void main(String[] args) {

        ILove love = null;

         /*love = (int a,int b,int c) -> {
                System.out.println("i love you -->" +a);
                System.out.println("i love you -->" +b);
            };*/

        //简化1 去掉参数类型
        love=(a,b,c) ->{
            System.out.println("i love you -->" +a);
            System.out.println("i love you -->" +b);
        };
        //简化2 去掉括号 :单个参数才可以去掉括号!
       /* love= a -> {
            System.out.println("i love you -->" +a);
        };*/
        //简化3 去掉花括号
        love = (a,b,c) -> System.out.println("i love you -->" +a);

        /**
         * 总结
         * lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,用代码块包裹
         * 前提是接口为函数式接口  函数式接口:只能有一个方法的接口是函数式接口
         * 多个参数 可以去掉参数类型,要去掉就都去掉,必须加上括号!
         */

        love.love(521,2,3);
    }

}

//定义一个函数式接口
interface ILove{
    void love(int a, int b, int c);
}


i love you -->521
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小尹^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值