Java创建多线程的四种常用方式

提醒:下文内容仅就总结多线程的创建方式,不考虑线程安全问题,且为了直观,在异常处理方面大量省略

一.程序,进程,线程的基本概念


 这里只要做简单的了解即可,红字部分有印象就行,详细内容在虚拟机部分做具体解释

二.创建多线程的四种方式(以多线程抢票为背景)

①在JDK5.0之前:

 方式一:继承Thread类

    //1.创建一个子类继承Thread
    class Mythread extends Thread{
    private static int ticket=100;

    //2.重写run方法
    @Override
    public void run() {
        while (true){
            if(ticket>=1){
                System.out.println(getName()+"抢到票"+ticket);
                ticket--;
            }
            else{
                System.out.println(getName()+"票已售罄");
                break;
                    }
            }

        }
    }

    public class Test1  {
        public static void main(String[] args) {
            
           // 3.实例化子类对象
            Mythread t1= new Mythread();
            Mythread t2= new Mythread();
            t1.setName("线程一");
            t2.setName("线程二");


           // 4.start开启线程
            t1.start();
            t2.start();
        }
    }

总结:继承Thread创建多线程的步骤:
  1.创建一个子类继承Thread
  2.重写run方法
  3.实例化子类对象
  4.start开启线程


 方式二:实现Runnable接口

    //1.创建一个实现Runnable接口的类
    class Mythread implements Runnable{
    private int ticket=100;
    //2.重写run方法
    @Override
    public void run() {
        while (true){
            if(ticket>=1){
                System.out.println(Thread.currentThread().getName()+"抢到票"+ticket);
                ticket--;
            }
            else {
                  System.out.println(Thread.currentThread().getName()+"票已售罄");
                  break;
            }
        }
    }   
}
    public class Test1 {
        public static void main(String[] args) {
            //3.创建一个实现类的对象
            Mythread t= new Mythread();
            /*4.每个线程各自创建一个以实现类对象为参数的Thread  
            类的对象*/
            Thread t1=new Thread(t);
            Thread t2=new Thread(t);
            t1.setName("线程一");
            t2.setName("线程二");
            //5.start开启进程
            t1.start();
            t2.start();
        }
    }

总结:继承Thread创建多线程的步骤:
  1.创建一个实现Runnable接口的类
  2.重写run方法
  3.创建一个实现类的对象
  4.每个线程各自创建一个以实现类对象为参数的Thread类的对象
  5.start开启进程


关于Thead带参构造器的源码:

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

不难发现,其参数必须是Runnable接口实现类的对象

注:相比于继承Thread类,方式二可以直接实现数据共享,方式一需要用static修饰成员变量(这一点在讲同步的时候尤其重要)


②在JDK5.0新增:

 方式三:借助FutureTask类和Callable接口

    //1.创建一个实现Callable接口的类
    class MyThread implements Callable {
        //2.重写call函数(由于多态,Obj的返回值类型可以自动向下转化)
        @Override
        public Object call() throws Exception {
            int sum=0;
            for (int i = 0; i <100 ; i++) {
                if (i % 2 == 0) {
                    sum += i;
                    System.out.println(i);
                }
            }
            return sum;
        }
    }
    public class Test1 {
        public static void main(String[] args) throws InterruptedException, UnknownHostException {
            //3.创建一个实现类的对象
            MyThread myThread=new MyThread();
            //4.创建一个FutureTask的对象,传入Callable实现类的对象
            FutureTask futureTask=new FutureTask(myThread);
            //5.创建一个Thread类的对象传入对象futureTask并start
            new Thread(futureTask).start();

            //6.如果需要返回值,再调用futureTask.get()来取返回值
            try {
                Object sum=futureTask.get();
                System.out.println("总和为"+sum);
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

总结:
  1.创建一个实现Callable接口的类
  2.重写call方法
  3.创建一个实现类的对象
  4.创建一个FutureTask的对象,传入Callable实现类的对象
  5.创建一个Thread类的对象传入对象futureTask并start
  6.如果需要call函数的返回值,需要调用future.get()的方法

注:Callable可以简单认为是Runnable的升级版,Callable允许有返回值功能更强大


关于FutureTask构造器的源码解析


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tidEObNM-1622460716694)( https://i.loli.net/2020/07/20/mShDs6cjOlNERJg.png)]

不难发现,FutrueTask其实继承了Runnable,所以在Tread实例化的时候可以直接带FutureTask的对象,并且上图中的构造器中对callable进行了回调


 方式四:调用线程池来实现多线程(开发中主要还是用线程池)

    //1.创建一个实现Runnable接口的类
    class Mythread implements Runnable {
    private int ticket=100;
    //2.重写run方法
    @Override
    public void run() {
        while (true){
        if(ticket>=1){
            System.out.println(Thread.currentThread().getName()+"票"+ticket);

            ticket--;
        }
        else{
            System.out.println(Thread.currentThread().getName()+"售罄了");
            break;
                }
        }
        }
    }

    public class Test1 {
        public static void main(String[] args) {
            //3.提供指定线程数量的线程池
            ExecutorService service=Executors.newFixedThreadPool(10);
            //service.submit(new Mythread());//适用于Callable
            
    //4.执行指定的线程操作需要提供实现Runnable接口或Callable接口的类
            service.execute(new Mythread());//适用于Runnable
            service.execute(new Mythread());
        //关闭线程池
            service.shutdown();
        }
    }

线程池的好处:


注:用survice.getClass()可以找到survice的实现类,可以发现是ThreadPoolExxcutor,然后上属的方法要通过强转才能用:
ThreadPoolExxcutor survice1=(ThreadPoolExxcutor) survice;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值