java之多线程详解(基础版)

1.什么是进程?

1.1进程就是执行程序的一次执行过程,他是应该动态的概念,是系统分资源分配的单位。

2.什么是线程

2.1一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程是CPI调度和执行的单位。

3.创建线程的方式

3.1继承Thread类,重写run()方法,调用start开启线(不建议使用,避免OPP的单继承局限性)案例

        3.1.1创建一个maven项目 导入依赖

 <dependencies>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
    </dependencies>

       3.1.2 准备一个文件下载工具类(来自刚刚导入的依赖)

                

package com.sj;

import org.apache.commons.io.FileUtils;

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

/**
 *  文件下载工具类
 * @author SheJun
 */
public  class DownLoader {
        public void downLoader(String url,String name){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                System.out.println("io异常");
                e.printStackTrace();
            }
        }
    }

        3.1.3写一个类继承Thread类,重写run()方法,调用start开启线(),测试

package com.sj;


/**
 * @Author sj
 * @Date: 2022/04/04/ 22:28
 * @Description
 */
public class ThreadTest extends Thread {
    /**
     * 文件路径
     */
    private String url;

    /**
     * 文件名
     */
    private String name;

    /**
     * 构造器注入
     * @param url
     * @param name
     */
    public ThreadTest(String url,String name){
        this.url =url;
        this.name = name;
    }

    /**
     * 覆写run方法
     */
    @Override
    public void run() {
        DownLoader downLoader = new DownLoader();
        downLoader.downLoader(url,name);
        System.out.println("下载的文件的名字:"+name);
    }

    /**
     * 写一个主线程
     * @param args
     */
    public static void main(String[] args) {

        ThreadTest threadTest1 = new ThreadTest("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/09/08/kuangstudya9f1a304-0940-45b7-9e6d-f1d4b46a155c.jpg","1.jpg");
        ThreadTest threadTest2 = new ThreadTest(" https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudyb62b0ccb-55b5-4572-b067-347314beac15.jpg","2.jpg");
        ThreadTest threadTest3 = new ThreadTest("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudy69ec9992-bed7-4eec-a550-5fe2aeb44737.jpg","3.jpg");
        threadTest1.start();
        threadTest2.start();
        threadTest3.start();
    }
}

 我们预想的先下载1,然后2,3 但是这里并没有去这样去执行,所以说,当线程开启时,不是马上去执行的,需要我们的cpu调度去执行,谁先得到就先执行!

3.2.实现Runable接口,覆写run方法,传入目标对象到Thread类,调用start启动(建议使用,避免了单继承的局限性)

        3.2.1 修改上面代码 如下

        

package com.sj;


/**
 * @Author sj
 * @Date: 2022/04/04/ 22:28
 * @Description
 */
public class RunnableTest implements Runnable {
    /**
     * 文件路径
     */
    private String url;

    /**
     * 文件名
     */
    private String name;

    /**
     * 构造器注入
     * @param url
     * @param name
     */
    public RunnableTest(String url, String name){
        this.url =url;
        this.name = name;
    }

    /**
     * 覆写run方法
     */
    @Override
    public void run() {
        DownLoader downLoader = new DownLoader();
        downLoader.downLoader(url,name);
        System.out.println("下载的文件的名字:"+name);
    }

    /**
     * 写一个主线程
     * @param args
     */
    public static void main(String[] args) {

        RunnableTest threadTest1 = new RunnableTest("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/09/08/kuangstudya9f1a304-0940-45b7-9e6d-f1d4b46a155c.jpg","1.jpg");
        RunnableTest threadTest2 = new RunnableTest(" https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudyb62b0ccb-55b5-4572-b067-347314beac15.jpg","2.jpg");
        RunnableTest threadTest3 = new RunnableTest("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudy69ec9992-bed7-4eec-a550-5fe2aeb44737.jpg","3.jpg");
         new Thread(threadTest1).start();
        new Thread(threadTest2).start();
        new Thread(threadTest3).start();
    }
}

测试,成功

3.3实现Callable接口,重写call方法,抛出异常,创建目标对象,创建执行服务,提交执行,关闭服务(案例)

        3.3.1代码如下图

        

 

package com.sj;


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.util.concurrent.Executors.*;

/**
 * @Author sj
 * @Date: 2022/04/04/ 22:28
 * @Description
 */
public class CallableTest3 implements Callable<Boolean> {
    /**
     * 文件路径
     */
    private String url;

    /**
     * 文件名
     */
    private String name;
    /**
     * 构造器注入
     * @param url
     * @param name
     */
    public CallableTest3(String url, String name){
        this.url =url;
        this.name = name;
    }

    public static void main(String[] args) {
        CallableTest3 threadTest1 = new CallableTest3("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/09/08/kuangstudya9f1a304-0940-45b7-9e6d-f1d4b46a155c.jpg","1.jpg");
        CallableTest3 threadTest2 = new CallableTest3(" https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudyb62b0ccb-55b5-4572-b067-347314beac15.jpg","2.jpg");
        CallableTest3 threadTest3 = new CallableTest3("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudy69ec9992-bed7-4eec-a550-5fe2aeb44737.jpg","3.jpg");
        // 创建执行服务
        ExecutorService executorService = newFixedThreadPool(3);
        // 提交执行
        executorService.submit(threadTest1);
        executorService.submit(threadTest2);
        executorService.submit(threadTest3);
        // 关闭服务
        executorService.shutdownNow();
    }

    @Override
    public Boolean call() throws Exception {
        DownLoader downLoader = new DownLoader();
        downLoader.downLoader(url,name);
        System.out.println("下载的文件的名字:"+name);
        return true;
    }
}

 由效果图我们可以出Callable也可以创建线程,(嘿嘿其实在这里我们如果点进源码去看这里其实用到了代理模式,下一遍我将告诉大家怎么去实现静态代理和jdk动态代理!)

4. 多线程操作多一个对象(初识并发问题,抢票案例)

        4.1代码如下,在里面我们实现了Runnable接口,然后模拟抢票

        

package com.sj;


/**
 * @Author sj
 * @Date: 2022/04/04/ 22:28
 * @Description
 */
public class RunnableTest2 implements Runnable {
    /**
     * 票数
     */
    private int numbers= 10;
    @Override
    public void run() {
        while (true){
            if (numbers<=0){
                break;
            }
            // 模拟抢票延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+numbers--+"票");
        }
    }

    public static void main(String[] args) {
        RunnableTest2 runnable1 = new RunnableTest2();
        new Thread(runnable1,"黄牛").start();
        new Thread(runnable1,"小红").start();
        new Thread(runnable1,"薛之谦").start();
    }
}

 测试结果我们可以看出,当我们多个线程去操作一个资源的时候,会出现了线程不安全,数据混乱的情况!(初始并发问题)!

希望可以帮助到小伙伴们

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值