Java线程的三种创建方式

导语:在Java中,多线程是非常重要的知识点,在笔试面试、实际应用等场合都是高频的知识点。本篇文章是我学习过程中一些知识点的理解分享,我将以案例来展示Java线程的创建。希望文章能对你的学习有所帮助。

(一)程序、进程、线程的理解:

①程序:顾名思义,程序就是我们所编写的Java代码。

②进程:在我们将编写的java代码运行起来,就是进程了。

③线程:在进程的内部,有多个线程的任务进行运行。

        在我们日常冲浪的时候,我们可能会用到自带的电脑管家,例如联想电脑管家、腾讯电脑管家等。打开电脑管家,这就是一个进程,在电脑管家里面,有优化加速、垃圾清理......,我们可以同时优化加速、垃圾清理等操作,这时候线程就启动起来了。

 (Fig.1:联想电脑管家)

        如果在优化加速、垃圾清理等操作一半时候,我们终止了操作,那么就意味着这个线程被杀死了。

(二)案例的引入

 本次案例:京东举行了一次茅台抢购活动,限量10瓶。有来自北京、上海、广州、深圳地区的各100名用户参与了抢购,模拟一次抢购过程,看哪些用户抢到了茅台。

        我们将用三种线程创建方式(实现Callable接口未实现)来完成案例演示,希望能够用案例实践来让大家对学习创建线程的知识点理解得更加透彻。

(三)线程的三种创建方式

所谓的线程简单的理解,就是在争抢资源,在争抢CPU资源。每个线程分得一定的时间片来使用CPU,然后反复的进行资源使用,在我们的宏观层面,就形成了多个线程都在运行的假象。

(1)方式一:继承Thread类

1.创建方式一线程的代码实现:

package com.suhuiteng.Study_Thread;

/**
 * @Auther:suhuiteng
 * @Data: 2021/9/29 - 09 - 29 - 10:39
 * @Description:com.suhuiteng.Study_Thread
 * @Vesion:
 */
public class Thread01 {
    public static void main(String[] args) {
        ThreadTest01 tt1=new ThreadTest01();    //创建具体线程
        //上面的相当于:Thread tt1=new ThreadTest01();
        //tt1.run();    相当于一个普通的方法
        tt1.start();    //应该用start()方法启动线程
    }
}

class ThreadTest01 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            System.out.println("子线程"+i);
        }
    }
}

        为了能够更加明了的看出我们这个线程是有在抢资源的具体表现,我们再完善下代码,让继承Thread类和main()争抢资源,代码实现如下:

package com.suhuiteng.Study_Thread;

/**
 * @Auther:suhuiteng
 * @Data: 2021/9/29 - 09 - 29 - 10:39
 * @Description:com.suhuiteng.Study_Thread
 * @Vesion:
 */
public class Thread01 {
    public static void main(String[] args) {
        ThreadTest01 tt1=new ThreadTest01();    //创建具体线程
        //上面的相当于:Thread tt1=new ThreadTest01();
        //tt1.run();    相当于一个普通的方法
        tt1.start();    //应该用start()方法启动线程

        /*****main()中抢资源*******/
        for (int i = 0; i <10 ; i++) {
            System.out.println("主线程"+i);
        }

    }
}

class ThreadTest01 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            System.out.println("子线程"+i);
        }
    }
}

         我们的预期效果是子线程和主线程交替打印。实际在控制台观察到,主线程和子线程是有在争抢资源:

2.案例程序代码:

package com.suhuiteng.Study_Thread;

/**
 * @Auther:suhuiteng
 * @Data: 2021/9/28 - 09 - 28 - 8:33
 * @Description:com.suhuiteng.Study_Thread
 * @Vesion:
 */
public class mythread_01 {
        public static void main(String[] args) {
            /****创建线程,模拟各个地区用户的抢购*****/
            Thread th1=new BuyLiquorThread("北京");
            th1.start();    //启动北京线程
            Thread th2=new BuyLiquorThread("上海");
            th2.start();    //启动上海线程
            Thread th3=new BuyLiquorThread("广州");
            th3.start();    //启动广州线程
            Thread th4=new BuyLiquorThread("深圳");
            th4.start();    //启动深圳线程
        }
    }

/**
 * 抢购线程
 */

class BuyLiquorThread extends Thread{
        //创建构造器
        public BuyLiquorThread(String Name){
            super.setName(Name);//设置当前线程的名字
        }

        static int LiquorNumber=10;   //模拟白酒数量,记得加上static,在四个创建模拟地区的线程才能够共享白酒数量

        @Override
        public void run() {
            for (int i = 1; i <=100 ; i++){
                if(LiquorNumber>0){
                    System.out.println(super.getName()+"用户"+i+"抢到了第"+ LiquorNumber-- +"瓶茅台酒");
                }
            }

        }
    }

编译结果:

(2)方式二:实现Runable接口

1.创建方式一线程的代码实现:

package com.suhuiteng.Study_Thread;

/**
 * @Auther:suhuiteng
 * @Data: 2021/9/29 - 09 - 29 - 10:58
 * @Description:com.suhuiteng.Study_Thread
 * @Vesion:
 */
public class Thread02 {
    public static void main(String[] args) {
        ThreadTest02 tt2=new ThreadTest02();    //具体线程
        Thread tdd02=new Thread(tt2);    //因为具体线程tt2没有start,我们将tt2传入Thread来实现start启动
        tdd02.start();    //启动线程
    }
}

class ThreadTest02 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            System.out.println("子线程"+i);
        }
    }
}

        同上,为了观察子线程和主线程争抢资源的效果,我们完善代码(代码因篇幅未上传,读者可以自己学习完善下),观察到控制台如下:

2.案例程序代码:

package com.suhuiteng.Study_Thread;

/**
 * @Auther:suhuiteng
 * @Data: 2021/9/28 - 09 - 28 - 8:37
 * @Description:com.suhuiteng.Study_Thread
 * @Vesion:
 */
public class mythread_02 {
    public static void main(String[] args) {
        BuyLiquorThread02 pt=new BuyLiquorThread02();
        Thread by1= new Thread(pt,"北京");
        by1.start();    //启动北京线程
        Thread by2= new Thread(pt,"上海");
        by2.start();    //启动上海线程
        Thread by3= new Thread(pt,"广州");
        by3.start();    //启动广州线程
        Thread by4= new Thread(pt,"深圳");
        by4.start();    //启动深圳线程


    }
}

class BuyLiquorThread02 implements Runnable{
    int LiquorNumber=10;    //模拟白酒数量,模拟的地区线程是共享BuyLiquorThread02,不用加上static
    @Override
    public void run() {
        for (int i = 1; i <=100 ; i++) {
            if(LiquorNumber>0){
                //设置名字用 Thread.currentThread().getName()
                System.out.println(Thread.currentThread().getName()+"用户"+i+"抢到了第"+ LiquorNumber-- +"瓶茅台酒");
            }
        }
    }
}

编译结果:

(3)方式三:实现Callable接口

        接下来是第三种创建方式,我们已经在上面学习到了两种线程的创建方式,那没为什么要再引入实现Callable接口来进行创建线程呢?

继承Thread实现Runable接口两种方式中,存在着一定的局限性:

①Run( )方法只能是Void,而不能有返回。

②Run( )方法不能够抛出异常。

        为了能够有返回值和能够抛出异常,所以在JDK1.5之后就引进了实现Callaable接口的方式。我们进入查看Callable接口:

 Callable接口创建线程也存在着一定的缺点,就是创建线程比其他两种方式复杂。

创建的过程如下:

public class mythread_03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建过程如下:
        RadomThread rt=new RadomThread();   //创建实例
        FutureTask ft=new FutureTask(rt);   //通过FutureTask方法将RadomThread和Thread关联,使得RadomThread可以实现Start()启动
        Thread td=new Thread(ft);   //创建Thread,使得RadomThread和Thread关联
        td.start(); //启动线程
        Object o=ft.get();
        System.out.println(o);

    }
}
//RadomThread 是一个获取随机数线程
class RadomThread implements Callable<Integer>{
    @Override
    public Integer call(){
        return new Random().nextInt(10);
    }
}

创建实现Callable接口线程:

实例线程名 实例名=new 实例线程名()

FutureTask futuretask名=new FutureTask(实例名);

Thread thread名=new Thread(futuretask名);

案例程序代码:

因对知识的体系了解不够透彻,暂未使用实现Callable接口实现案例分析。

结语:本文主要是通过案例来演示线程的三种创建方式的学习分享,对于线程的整体的逻辑认识可能仍有所欠缺。欢迎指正,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Docker启动RabbitMQ,你可以按照以下步骤进行操作: 1. 首先,在Docker Hub上搜索RabbitMQ镜像,你可以使用命令`docker search rabbitmq`来查找可用的镜像。\[1\] 2. 使用以下命令来启动RabbitMQ容器,并将容器的15672端口映射到主机的15672端口(用于管理界面),以及将容器的5672端口映射到主机的5672端口(用于AMQP连接):\[2\] ``` docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:latest ``` 3. 如果你想要安装RabbitMQ的可视化插件,你可以使用以下命令进入容器内部:\[2\] ``` docker exec -it <container_id> /bin/bash ``` 然后运行以下命令来启用RabbitMQ管理器插件: ``` rabbitmq-plugins enable rabbitmq_management ``` 4. 如果你想要更改默认的管理员密码,你可以使用以下命令:\[3\] ``` rabbitmqctl change_password admin 'new_password' ``` 5. 最后,如果你遇到了RabbitMQ Management API返回状态码500的问题,你可以进入容器并执行以下命令:\[3\] ``` echo "management_agent.disable_metrics_collector = false" > /etc/rabbitmq/conf.d/management_agent.disable_metrics_collector.conf docker restart rabbitmq ``` 这样,你就可以使用Docker成功启动RabbitMQ了。 #### 引用[.reference_title] - *1* *2* *3* [Docker启动rabbitmq最详细步骤](https://blog.csdn.net/weixin_57004864/article/details/128782579)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值