吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2458|回复: 6
收起左侧

[Java 转载] 多线程实现,并发,静态代{过}{滤}理以及lambda表达式的推演知识详解

[复制链接]
黑白客 发表于 2021-2-26 15:33
本帖最后由 黑白客 于 2021-2-26 15:36 编辑

java多线程
线程简介
线程实现
初识并发问题
实现Callable接口
静态代{过}{滤}理
Lambda表达式

java多线程

线程简介

多线程:比如我们可以在电脑上一边听音乐,一边浏览网页等等。

  • 核心概念
    • 程序是静态的,一个程序跑起来之后就会变成一个进程,一个进程里可以有多个线程。main方法是主线程
    • 线程就是独立的执行路径
    • 在程序运行时,即使自己没有创建线程,后台也会有多个线程,如:主线程,gc线程(垃圾回收机制)
    • main方法为主线程,为系统的入口,用于执行整个程序。
    • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度。调度器是与电脑操作系统紧密相关的,先后顺序是不能人为干预的。
    • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。
    • 线程会带来额外的开销,如cpu调度时间,并发控制开销。
    • 每个线程在自己工作内存交互,内存控制不当会造成数据不一致

线程实现

  • 方法一
    • 创建一个类,继承Thread类。实现其run()方法、run方法就是线程体
    • 在main方法中创建类的对象,调用start()方法。实现多线程。如果调用run方法,就不会实现多线程。是单线程。
    • 线程创建之后并不会立即执行,需要cpu的调度安排。cpu在同一时间只能调用一个线程。

网图下载:利用多线程,下载多个网图

package com.wang.threadDemo;

import org.apache.commons.io.FileUtils;

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

/**
 * @author: 王海新
 * @Date: 2021/2/22 11:24
 * @Description:下载网图
 */
public class TestThread2 extends Thread {
    private String url;
    private String name;

    TestThread2(String url,String name){
        this.url = url;
        this.name = name;
    }
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.download(url,name);
        System.out.println("文件被下载了" + name);
    }
    public static void main(String[] args) {
        TestThread2 test1 = new TestThread2("https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/cdbf6c81800a19d86524639732fa828ba61e4679.jpg", "1.jpg");
        TestThread2 test2 = new TestThread2("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20191221%2F19%2F1576927577-ezdtLhXcng.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557755&t=9c5d0cdc0fd6d2988b9522d0dab2f9c7", "2.jpg");
        TestThread2 test3 = new TestThread2("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20190819%2F10%2F1566182328-nwMPsxzGXL.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557823&t=e0da3b689853d27b1a26d2879faec7eb", "3.jpg");

        test1.start();
        test2.start();
        test3.start();

    }
}

/*********************************************************************************************************************
 * @Author:  王海新
 * @Date:  11:26  2021/2/22
 * @Version:  1.0.0
 * @Description:  下载器
 */
class  WebDownloader{
    //下载方法
    public void download(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            System.out.println("io出错,出错方法:WebDownload");
        }
    }
}
  • 第二种方法:实现Runable接口,推荐使用 避免单线程的局限性。
package com.wang.threadDemo;

import org.apache.commons.io.FileUtils;

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

/**
 * @author: 王海新
 * @Date: 2021/2/22 16:36
 * @Description: 实现Runnable接口
 *
 */
public class TestThread3 implements Runnable {
    private String url;
    private String name;

    TestThread3(String url,String name){
        this.url = url;
        this.name = name;
    }
    @Override
    public void run() {
        WebDownloader1 webDownloader = new WebDownloader1();
        webDownloader.download1(url,name);
        System.out.println("文件被下载了" + name);
    }
    public static void main(String[] args) {

        TestThread3 test1 = new TestThread3(
                "https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/cdbf6c81800a19d86524639732fa828ba61e4679.jpg", "4.jpg");
        TestThread3 test2 = new TestThread3(
                "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20191221%2F19%2F1576927577-ezdtLhXcng.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557755&t=9c5d0cdc0fd6d2988b9522d0dab2f9c7", "5.jpg");
        TestThread3 test3 = new TestThread3(
                "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20190819%2F10%2F1566182328-nwMPsxzGXL.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557823&t=e0da3b689853d27b1a26d2879faec7eb", "6.jpg");

        new Thread(test1).start();
        new Thread(test2).start();
        new Thread(test3).start();

    }
}

/*********************************************************************************************************************
 * @Author:  王海新
 * @Date:  11:26  2021/2/22
 * @Version:  1.0.0
 * @Description:  下载器
 */
class  WebDownloader1 {
    //下载方法
    public void download1(String url, String name) {

        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("io出错,出错方法:WebDownload1");
        }
    }
}

基本上和继承Thread类相同,只是在调用的时候。

new 实现类

new Thread(实现类名).start();来调用

初识并发问题

通过以下程序,可以发现在抢票的过程中,多个线程操作

同一个资源,会出现错误

package com.wang.threadDemo;

/**
 * @author: 王海新
 * @Date: 2021/2/22 17:07
 * @Description: 多个线程同时操作一个对象
 * 买火车票的例子
 *
 * 发现问题:多个线程操作同一个资源的情况下,不安全
 */
public class TestThread4 implements Runnable{
    private int ticketNumbel = 10; //火车票
    @Override
    public void run() {
        while (true){
            if (ticketNumbel <= 0) {
                break;
            }
            //添加延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 拿到了第" + ticketNumbel-- + "张票");
        }
    }

    public static void main(String[] args) {
        TestThread4 ticket = new TestThread4();

        new Thread(ticket,"小明").start();
        new Thread(ticket,"老师").start();
        new Thread(ticket,"黄牛党").start();
        new Thread(ticket,"键盘侠").start();
    }
}

利用以下龟兔赛跑的案例,来巩固一下多线程的概念

package com.wang.threadDemo;

/**
 * @author: 王海新
 * @Date: 2021/2/22 17:26
 * @Description: 龟兔赛跑
 *
 */
public class Race implements Runnable {

    private  static String winner;//胜利者
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //模拟兔子睡觉
            if (Thread.currentThread().getName().equals("兔子") && i == 90) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "--> 跑了 " + i +"步");
            //判断是否跑完一百步
            if (gameOver(i)) {
                break;
            }
        }
    }
/*********************************************************************************************************************
 * @Author:  王海新
 * @Date:  17:34  2021/2/22
 * @Version:  1.0.0
 * @Description:  判断是否结束比赛
 */
    private boolean gameOver(int steps){
        //判断是否存在胜利者
        if (winner != null) {//已经存在获胜者
            return true;
        }
        if (steps >= 100) {
            winner = Thread.currentThread().getName();
            System.out.println( winner + "获胜");
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();

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

实现Callable接口

package com.wang.threadDemo;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

/**
 * @author: 王海新
 * @Date: 2021/2/25 19:18
 * @Description:线程创建方式三:实现callable接口
 * 可以获取一个返回值
 * 可以抛出异常
 * 但是需要创建一个服务,通过服务提交
 */
public class TestCallable implements Callable<Boolean> {
    private String url;
    private String name;

    TestCallable(String url,String name){
        this.url = url;
        this.name = name;
    }
    @Override
    public Boolean call() {
        WebDownloader3 webDownloader = new WebDownloader3();
        webDownloader.download1(url,name);
        System.out.println("文件被下载了" + name);
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        TestCallable test1 = new TestCallable(
                "https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/cdbf6c81800a19d86524639732fa828ba61e4679.jpg", "4.jpg");
        TestCallable test2 = new TestCallable(
                "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20191221%2F19%2F1576927577-ezdtLhXcng.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557755&t=9c5d0cdc0fd6d2988b9522d0dab2f9c7", "5.jpg");
        TestCallable test3 = new TestCallable(
                "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20190819%2F10%2F1566182328-nwMPsxzGXL.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557823&t=e0da3b689853d27b1a26d2879faec7eb", "6.jpg");

        //1 创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(3);

        //2 提交执行
        Future<Boolean> s1 = ser.submit(test1);
        Future<Boolean> s2 = ser.submit(test2);
        Future<Boolean> s3 = ser.submit(test3);

        //3 获取结果
        boolean q = s1.get();
        boolean q1 = s2.get();
        boolean q2 = s3.get();

        //4 关闭服务
        ser.shutdown();
    }
}

/*********************************************************************************************************************
 * @Author:  王海新
 * @Date:  19:21  2021/2/25
 * @Version:  1.0.0
 * @Description:  下载器
 */
class  WebDownloader3 {
    //下载方法
    public void download1(String url, String name) {

        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("io出错,出错方法:WebDownload1");
        }
    }
}

静态代{过}{滤}理

看一个结婚的案例

package com.wang.threadDemo1;

/**
 * @author: 王海新
 * @Date: 2021/2/26 09:49
 * @Description: 静态代{过}{滤}理模式总结
 * 真实对象和代{过}{滤}理对象都要实现同一个接口
 * 代{过}{滤}理对象要代{过}{滤}理真实角色
 *
 * 好处:
 *  代{过}{滤}理对象可以做很多真实对象做不了的事情
 *  真实对象专注做自己的事情
 */
public class StacticProxy {
    public static void main(String[] args) {
        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
        //还可以简写为一行代码
        // new WeddingCompany(new You()).HappyMarry();
    }
}

//结婚的接口
interface Marry{
    /*********************************************************************************************************************
     * @Author:  王海新
     * @Date:  9:53  2021/2/26
     * @Version:  1.0.0
     * @Description: 开心的结婚
     *     人间四大喜事
     *     * 久旱逢甘露
     *     * 他乡遇故知
     *     * 洞房花烛夜
     *     * 金榜题名时
     */
    void HappyMarry();
}

/*********************************************************************************************************************
 * @Author:  王海新
 * @Date:  9:54  2021/2/26
 * @Version:  1.0.0
 * @Description:  真实角色,你去结婚
 */
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("我要结婚啦");
    }
}
/*********************************************************************************************************************
 * @Author:  王海新
 * @Date:  9:55  2021/2/26
 * @Version:  1.0.0
 * @Description:  代{过}{滤}理角色,帮助你结婚
 * 他会在你原来实现功能之前之后添加新的东西
 */
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 after() {
        System.out.println("收尾款");
    }

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

Lambda表达式

理解函数式接口是学习Lamda表达式的关键所在

  • Lamda函数式接口的定义:
    • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
    • 对于函数式接口,就可以通过lambda表达式来创建接口
  • lambda推演过程
package com.wang.threadDemo1;

/**
 * @author: 王海新
 * @Date: 2021/2/26 11:00
 * @Description: 推演lambda表达式
 */
public class lambda {
    //2.定义一个静态内部类,实现
    static class Like2 implements Ilike{
        @Override
        public void lambda() {
            System.out.println(2);
        }
    }

    public static void main(String[] args) {
        //1.创建外部类对象实现
        Ilike like = new Like();
        like.lambda();

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

        //3.定义一个局部内部类实现
        class Like3 implements Ilike{
            @Override
            public void lambda() {
                System.out.println(3);
            }
        }
        Like3 like1 = new Like3();
        like1.lambda();

        //4.匿名内部类,没有类的名称,必须借助类的接口或者父类
        like = new Ilike(){
            @Override
            public void lambda() {
                System.out.println(4);
            }
        };
        like.lambda();

        //5.使用lambda简化
        like = () -> {
            System.out.println("5");
        };
        like.lambda();
    }

}

//定义一个函数式接口
interface Ilike{
    void lambda();
}

//定义一个实现类
class Like implements Ilike{

    @Override
    public void lambda() {
        System.out.println(1);
    }
}
  • lambda表达式简化
package com.wang.threadDemo1.lambda;

/**
 * @author: 王海新
 * @Date: 2021/2/26 11:33
 * @Description: 函数式接口的有参方法 简化
  * 多个参数也可以去掉参数类型,但是要去掉都去掉。必须加上括号
 */
public class lambda2 {
    public static void main(String[] args) {
        //1
        Iove iove = (int a) ->{
            System.out.println("爱你"+a);
        };
        iove.honey(111);

        //2 去掉形参的参数类型
        Iove iove1 = (a) ->{
            System.out.println("爱你"+a);
        };
        iove1.honey(222);

        //3 去掉括号(无参方法不可以去掉
        Iove iove2 = a ->{
            System.out.println("爱你"+a);
        };
        iove2.honey(333);

        //4 去掉大括号(假如你的代码有多行,就不可以去掉大括号,因为一个分号就表示结束了。没办法添加新的一行
        Iove iove3 = a ->  System.out.println("爱你"+a);
        iove3.honey(444);
    }

}

interface Iove{
    void honey(int a);
}

免费评分

参与人数 2热心值 +2 收起 理由
jacklee2014 + 1 我很赞同!
Yic0313 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

aa361611002 发表于 2021-2-26 16:17
楼主头像好评
白衣国度 发表于 2021-2-26 16:53
JsFuck攻城狮 发表于 2021-2-26 17:43
nj001 发表于 2021-2-26 23:07
java的函数式编程让人心累
 楼主| 黑白客 发表于 2021-2-27 11:52
nj001 发表于 2021-2-26 23:07
java的函数式编程让人心累

嗯?是吗?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 19:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表