首页 > 编程语言 >Java多线程-Lesson01-线程的创建

Java多线程-Lesson01-线程的创建

时间:2023-06-18 20:45:21浏览次数:55  
标签:Java start 线程 run 多线程 方法 public

线程创建的三种方式

继承Thread类

步骤:

  • 继承Thread类
  • 重写run()方法
  • 调用start()开启线程

重写run()方法:

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("run():"+i);
        }
    }

 

run()方法里面就是我们多线程要执行的代码

但是调用的时候不能直接调用run()方法,而是采用start()方法

区别是:

直接调用run()方法的执行还是单线程的,cpu会先去执行run()方法,再执行回去main()方法

而调用start()方法,则是再执行到start()方法后直接开启另外一条线程,此时自己的线性依旧执行mian()方法,另外一条线程就去执行run方法

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

 public static void main(String[] args) {
        ExtendThread thread = new ExtendThread();
        thread.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("main():"+i);
        }
    }

 

如上代码:

先开启的是run()方法在mian()方法的输出前面,

如果是单线程会怎么执行呢?很显然它会把run方法执行完毕了,再去mian方法,那么我们的执行结果是什么:

 可以看到,main()方法和run()方法是交替执行的,并且main()方法的输出要先执行,

但是,我们的调用是先调用的run()方法啊,这是为什么呢?

这就要涉及到线程和进程的关系了,线程是程序的执行体,而进程是系统分配时资源的拥有者,进程在执行依赖于主线程,也就是我们的main()线程的执行

不管怎么讲,main()线程都是在执行中的,而run()方法的线程需要cpu调度,然后开辟线程需要时间,所以这就是为什么多线程情况下,先调度run()方法,但是mian()方法却先执行

 如上图,

可以感觉到多线程和单线程的区别,多线程不再是等到调用方法执行完成以后才能执行自己的代码逻辑了

多线程下,它会通知cpu为这个方法单独开辟一个线程供它执行,两者在宏观上是一起执行的

也可以从图片上明显感受到两个线在一起向下执行的感觉

深入理解多线程(应用):

这是一个下载实例,给一个工具类一个url路径,然后让它去对应的地点下载,但是我们使用多线程下载,

每个线程下载一次,如果下载的顺序是我们调用的顺序,那么就是单线程,如果和我们调用的顺序不一致,那么就是多线程

代码附上:

public class ThreadDown extends Thread{
    private String url;
    private String name;

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

    @Override
    public void run() {
        ImageDown down = new ImageDown();
        down.downLoad(url,name);
        System.out.println("down:"+name);
    }

    public static void main(String[] args) {
        ThreadDown d1 = new ThreadDown("https://images.cnblogs.com/cnblogs_com/blogs/748669/galleries/2311207/o_230520101825_bachong.png","1.png");
        ThreadDown d2 = new ThreadDown("https://images.cnblogs.com/cnblogs_com/blogs/748669/galleries/2311207/o_230520101825_bachong.png","2.png");
        ThreadDown d3 = new ThreadDown("https://images.cnblogs.com/cnblogs_com/blogs/748669/galleries/2311207/o_230520101825_bachong.png","3.png");
        d1.start();
        d2.start();
        d3.start();
    }
}

class ImageDown{
    public void downLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            System.out.println("IO异常,未找到图片");
        }
    }
}

 

如上代码:

在main()方法中,我们的调用顺序是先下载1.png,然后下载2.png,最后下载3.png,如果是单线程肯定是这个顺序

我们看看结果如何:

 很显然,它不是我们的调用顺序,而是和cpu调用和资源大小有关系,调用顺序的时间对其影响很小很小

多线程的下载使得在宏观上这三张图片是一起下载的,对cpu利用率来讲是很高的,这也是为什么要使用多线程的原因

 实现Runnable接口

步骤:

  • 定义一个自己的类,实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程

编写一个类,实现Runnable接口:

public class RunnableImp implements Runnable

 

重写run()方法,与继承Thread类一样:

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("run():"+i);
        }
    }

 

创建线程对象Thread,调用start()方法启用:

 new Thread(new RunnableImp());

 

使用Runnabale接口实现的多线程结果图:

 

小结继承Thread类和实现Runnable接口:

继承Thread类:

  • 子类具有多线程能力
  • 启动线程:子类对象 . start()
  • 不建议使用,避免oop单继承的局限性

实现Runnable接口:

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

线程的并发问题:

当多个线程去使用同一公共资源,并且每个资源都尝试更改这个资源时会发生什么呢?

我们来简单的模拟一个购票系统,

一共10张票,小明,小红,小华一起去抢票,他们每个人使用的是不同的设备,所以肯定是一个多线程的问题,

代码实现:

public class TestRunnable implements  Runnable{
    private int ticket = 10;
    @Override
    public void run() {
        while (true){
            if (ticket<=0) {
                break;
            }
            System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket+"张票");
            ticket--;
        }
    }
    public static void main(String[] args) {
        new Thread(new TestRunnable(),"小明").start();
        new Thread(new TestRunnable(),"小红").start();
        new Thread(new TestRunnable(),"小华").start();
    }
}

 

我们可以看到一共就十张票,看看跑出来的结果有多少张票:

 如上图:

不仅数量不对,远超十张票,并且还有逆序的票,也就是一个人都拿到第七张票了,还有人能拿到第八张票,这明显不符合逻辑

数量很乱,而且也不合我们的逻辑,所以多线程解决问题是很高效,但是它的问题也不能忽略,那就是并发

这就是拿取票的顺序不一样导致的结果

关于这类问题,我们后期会专门讲解,大家也可以看看我以前写的博客线程中的线程并行预先了解

实现Callable接口(了解)

步骤:

  • 实现Callable接口,需要填写返回值
  • 重写call()方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务(开启几个):ExecutorService ser= Executors.newFixedThreadPool(2);
  • 提交执行:Future<Boolean> c1 = ser.submit(call1);
  • 获取结果:Boolean cs1 = c1.get();
  • 关闭服务:ser.shutdownNow();

代码实现:

public class TestCallable implements Callable<Boolean> {
    @Override
    public Boolean call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println("拿到了:"+i);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable call1 = new TestCallable();
        TestCallable call2 = new TestCallable();
        //开启服务
        ExecutorService ser= Executors.newFixedThreadPool(2);
        //提交执行
        Future<Boolean> c1 = ser.submit(call1);
        Future<Boolean> c2 = ser.submit(call2);
        //获取结果
        Boolean cs1 = c1.get();
        Boolean cs2 = c2.get();
        //关闭服务
        ser.shutdownNow();

    }
}

 

小结Callable的好处:

  1. 可以自定义返回值
  2. 可以抛出异常

代价:编写比其它两个方式要复杂

 

标签:Java,start,线程,run,多线程,方法,public
From: https://www.cnblogs.com/5ran2yl/p/17489398.html

相关文章

  • 必知必会:Java基础
    创建对象有几种方式(1)new创建对象;(2)反射创建对象;(3)采用clone机制;(4)序列化机制。创建反射对象的几种方式(1)类.class:通过 类名.class 创建反射获取对象; 类.class 是静态加载,是JVM编译时就要加载。Class<ClassDemo>oClass=ClassDemo.class;(2) object.getClass() :以 实......
  • java--多态
       ......
  • 基于JAVA物品租赁系统设计与实现
    物品租赁市场像是一块大蛋糕,现在网络购物趋势发展势头迅猛,网上物品租赁的市场开拓现在也在发展中,任何商家都需要抢占先机,开拓网上物品租赁市场,抢占网上交易市场份额。 所以本人设计了物品租赁系统,实现网上的物品租赁。根据本系统的研究现状和发展趋势,系统从需求分析、结构设计、数......
  • 基于JAVA公交路线查询系统
    进入21世纪以来,计算机通讯得到迅速发展,计算机的信息技术全面地普及到人类社会的各个方面,信息化成为世界经济和社会发展的大趋势。随着信息时代的发展,快捷高效的处理信息已成为各行各业的基本需求。在公交路线查询系统中,为满足其系统化,自动化,高效化的要求,需要设计一个有效的公交路......
  • 基于JAVA佳乐福购物商城系统
    随着传统的购物方式正在向网络化发展,出现了“网购”这种越来越受欢迎的新型消费方式。为了提高商品业务水平和效率,实现比电话订购更有效的销售业务,佳乐福购物商城应运而生。通过对购买商品流程和业务进行全面考察分析,结合目前最先进的软件开发技术,实现了购买商品的网络化管理。目前......
  • 基于JAVA物品租赁系统设计与实现
    物品租赁市场像是一块大蛋糕,现在网络购物趋势发展势头迅猛,网上物品租赁的市场开拓现在也在发展中,任何商家都需要抢占先机,开拓网上物品租赁市场,抢占网上交易市场份额。 所以本人设计了物品租赁系统,实现网上的物品租赁。根据本系统的研究现状和发展趋势,系统从需求分析、结构设计、数......
  • java--继承
       ......
  • 基于JAVA路障维修系统的设计与实现
    路障维修系统的设计与实现开发对提高期工作的效率和质量具有重要意义。本文从路障跟踪与维修系统的作用出发,详细阐述了路障跟踪与维修系统的用户部分和施工队部分开发、操作流程和涉及的一些关键技术。本文首先进行了项目概述,简单介绍了项目开发的背景、目的及意义,明确了路障跟踪与......
  • Java:使用bcrypt对密码加密和验证
    文档https://mvnrepository.com/artifact/org.mindrot/jbcrypthttp://www.mindrot.org/projects/jBCrypt/依赖<dependency><groupId>org.mindrot</groupId><artifactId>jbcrypt</artifactId><version>0.4</version><......
  • JavaScript-Vue
    2Vue2.1Vue概述通过我们学习的html+css+js已经能够开发美观的页面了,但是开发的效率还有待提高,那么如何提高呢?我们先来分析下页面的组成。一个完整的html页面包括了视图和数据,数据是通过请求从后台获取的,那么意味着我们需要将后台获取到的数据呈现到页面上,很明显,这就需要我们使......