JavaSE自学笔记Real_006(多线程基础)

JavaSE自学笔记Real_006(多线程基础)

多线程基础概念

1、程序时指令与数据的有序集合,其本身没有任何运行的含义,是一个静态的概念;
2、进程值执行程序的依次执行过程,他是一个动态的概念。是系统资源分配的单位;
3、在一个进程中包含有若干个线程,一个进程中至少有袷线程,线程时CPU调度和执行的单位。

注意:很多多线程时模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器,如果时模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就会产生同时执行的错觉。

多线程的创建

创建方式一:继承Thread类

//创建线程的方式一:继承Thread类,重写run()方法,调用start开启线程
public class TestThread1 extends Thread{
    /**
     * If this thread was constructed using a separate
     * {@code Runnable} run object, then that
     * {@code Runnable} object's {@code run} method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of {@code Thread} should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码--"+i);
        }
    }

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

        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();

        //调用start()方法开启线程

        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程--"+i);
        }
    }
}
小练习:多线程同时下载图片
package com.ThreadLearn.Demo002;

import com.ThreadLearn.Demo001.TestThread1;
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;
    }

    /**
     * If this thread was constructed using a separate
     * {@code Runnable} run object, then that
     * {@code Runnable} object's {@code run} method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of {@code Thread} should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, name);
        System.out.println("下载了文件。名字为:" + name);
    }

    public static void main(String[] args){
        TestThread2 t1 = new TestThread2("https://www.1fzz.com/content/uploadfile/202007/0ac61594015036.jpg", "1.jpg");
        TestThread2 t2 = new TestThread2("https://www.1fzz.com/content/uploadfile/202007/0ac61594015036.jpg", "2.jpg");
        TestThread2 t3 = new TestThread2("https://www.1fzz.com/content/uploadfile/202007/0ac61594015036.jpg", "3.jpg");

        t1.start();
        t2.start();
        t3.start();
    }
}

//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url, String name){
        try{
            FileUtils.copyURLToFile(new URL(url), new File(name));
        }catch(IOException e){
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题!");
        }

    }
}

创建方式二:Runnable接口实现

import com.ThreadLearn.Demo001.TestThread1;

//创建线程的方式二:实现runnable接口,重写run方法,执行线程须丢入runnable接口实现类,利用Thread类调用start方法
public class TestThread3 implements Runnable{
    /**
     * If this thread was constructed using a separate
     * {@code Runnable} run object, then that
     * {@code Runnable} object's {@code run} method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of {@code Thread} should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码--"+i);
        }
    }

    public static void main(String[] args) {
       //创建runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();

        //创建线程对象,通过线程对象来开启线程
        //Thread thread = new Thread(testThread3);
        //thread.start();
        new Thread(testThread3).start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程--"+i);
        }
    }
}

小结
1、继承Thread类:
(1)子类继承Thread类具备不哦线程能力
(2)启动线程:子类对象.strat();
(3)不建议使用,因为只能进行单继承
2、实现Runnable接口
(1)实现接口Runnable具有多线程能力
(2)启动线程:传入目标对象+Thread的对象.start();
(3)推荐使用,避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用

什么是并发问题

小例子:买火车票的问题

//多个线程同时操作同一个对象
//买火车票的例子

//发现问题:多个线程同时操作同一个资源,线程不安全,数据紊乱,这种现象称为并发问题
public class TestThread4 implements Runnable{

    //票数
    private int ticketNums = 10;

    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see Thread#run()
     */
    @Override
    public void run() {
        while(true){
            if(ticketNums <= 0){
                break;
            }

            //模拟延时
            try{
                Thread.sleep(200);
            }catch(InterruptedException e){
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- + "票");

        }
    }

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

        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛").start();

    }
}

运行结果:
可以看出,同一张票被多个人拿到,显然不符合要求

小明-->拿到了第8票
黄牛-->拿到了第9票
老师-->拿到了第10票
小明-->拿到了第6票
老师-->拿到了第5票
黄牛-->拿到了第7票
黄牛-->拿到了第4票
小明-->拿到了第4票
老师-->拿到了第3票
小明-->拿到了第2票
黄牛-->拿到了第2票
老师-->拿到了第1票

Process finished with exit code 0

创建方式三:实现callable接口

实现Callable接口:
1、实现callable接口,需要返回值类型
2、需要重写call方法,需要抛出异常
3、创建目标对象
4、创建执行服务ExecutorService ser = Executors.newFixedThreadPool(1);
5、提交执行 Future<Boolean> r1 = ser.submit(t1);
6、获取结果 boolean rs1 = r1.get();
7、关闭服务 ser.shutdown();


import org.apache.commons.io.FileUtils;

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

//线程的创建方式三:实现callable接口
/*
callable的好处:
1、可以定义返回值
2、可以抛出异常
 */
public class TestThread5 implements Callable<Boolean> {
    private String url; //网络图片的地址
    private String name; //保存的文件名

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

    /**
     * If this thread was constructed using a separate
     * {@code Runnable} run object, then that
     * {@code Runnable} object's {@code run} method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of {@code Thread} should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    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 {
        TestThread5 t1 = new TestThread5("https://www.1fzz.com/content/uploadfile/202007/0ac61594015036.jpg", "4.jpg");
        TestThread5 t2 = new TestThread5("https://www.wangyetuku.com/d/file/2019/016a6167e3df41c09e560b8336451075.jpg", "5.jpg");
        TestThread5 t3 = new TestThread5("https://www.1fzz.com/content/uploadfile/202007/0ac61594015036.jpg", "6.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{
            FileUtils.copyURLToFile(new URL(url), new File(name));
        }catch(IOException e){
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题!");
        }

    }
}

静态代理模式


//静态代理模式总结
//真实对象和代理对象都要实现接口
//代理对象要实现真实角色

//好处:
    //代理对象可以做某些真实对象做不了的事情
    //真实对象专注于做自己的事情

public class StaticProxy {
    public static void main(String[] args) {

        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
    }
}

interface Marry{
    void HappyMarry();
}

//真实角色
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("I am going to marry!");
    }
}

//重点分析这一段
//代理角色
class WeddingCompany implements Marry{

    private Marry target;

    public WeddingCompany(Marry target){
        this.target = target;
    }

    private void before(){
        System.out.println("Prepare the wedding.");
    }

    private void after(){
        System.out.println("Pay for the money.");
    }

    @Override
    public void HappyMarry() {
        //============================
        before();
        this.target.HappyMarry();
        after();
        //============================
    }
}

Lambda表达式基础(λ表达式)

为什么要用:
1、避免匿名内部类定义过多
2、可以让你的代码看起来更简洁
3、去掉了一些没有意义的代码,只留下核心的逻辑

推到lambda表达式,看他是怎么演变过来的:

1、外部实现类:

public class TestLambda1 {
    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();
    }
}

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

//2、实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("I like lambda!");
    }
}

2、静态内部类

public class TestLambda1 {

    //2、静态内部类
    static class Like implements ILike{
        @Override
        public void lambda2() {
            System.out.println("I like lambda2!");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda2();
    }
}

//1、定义一个函数式接口
interface ILike{
    void lambda2();
}

3、局部内部类(在main方法里面)

public class TestLambda1 {

    public static void main(String[] args) {

        //3、局部内部类
        class Like implements ILike{
            @Override
            public void lambda3() {
                System.out.println("I like lambda3!");
            }
        }

        ILike like = new Like();
        like.lambda3();

    }
}

//1、定义一个函数式接口
interface ILike{
    void lambda3();
}

4、匿名内部类

public class TestLambda1 {

    public static void main(String[] args) {

        //4、匿名内部类
        ILike like = new ILike() {
            @Override
            public void lambda4() {
                System.out.println("I like lambda4.");
            }
        };

        like.lambda4();

    }
}

//1、定义一个函数式接口
interface ILike{
    void lambda4();
}

//=====================================================
//简化写法:
//=====================================================
public class TestLambda1 {

    public static void main(String[] args) {

        //4、匿名内部类
        Runnable like = new Runnable() {
            @Override
            public void run() {
                System.out.println("I like lambda4.");
            }
        };
        
        like.run();
    }
}

5、lambda表达式简化

public class TestLambda1 {

    public static void main(String[] args) {

        //5、lambda表达式
        Runnable like = () -> {
            System.out.println("I like lambda5.");
        };

        like.run();

    }
}

带参数的lambda表达式简化

public class TestLambda2 {
    //带参数的接口实现简化
    /*
    总结:
         1、lambda表达式只能在只有有一行代码的情况下才能简化为银行,去电话括号,弱国有多行大妈,需要代码块包裹
        2、使用该表达式前提是为函数型接口,即接口中只有一个函数方法
        3、多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
    */

    public static void main(String[] args) {
        ILove love = (int a)-> {
            System.out.println("I love you --> " + a);
        };
        love.love(520);

        //简化1:简化参数类型
        love = (a)-> {
            System.out.println("I love you --> " + a);
        };
        love.love(520);

        //简化2:去掉括号
        love = a -> {
            System.out.println("I love you --> " + a);
        };
        love.love(521);

        //简化3:去掉花括号
        love = a -> System.out.println("I love you --> " + a);
        love.love(1314);
    }
}

interface ILove{
    void love(int a);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

仲子_real

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

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

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

打赏作者

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

抵扣说明:

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

余额充值