线程创建的几种方式

导读:本篇文章讲解 线程创建的几种方式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、线程创建的几种方式

常见的创建线程的方式有一下几种:

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口
  • 线程池创建

个人理解:

a.通过实现Runnable接口创建线程比继承Thread类创建线程好一点,因为每个类只能继承一个父类,但是可以实现多个接口。

b.Callable接口与Runnable接口的区别如下

  1. runnable方式时,多个线程间可以共享实例变量,callable方式则不行

  2. runnable方式没有返回值,callable有返回值

  3. runnable方式run方法的异常只能在内部消化,callable的call()方法允许抛出异常

c.线程并不是却多越好,因为线程的执行要抢占到CPU的执行权才能执行,如果在单核CPU的情况下,使用多线程反而不如单线程快。

d.线程的周期

  • NEW 新建状态,此时线程还没有运行线程中的代码
  • RUNNABLE 就绪状态;处于就绪状态的线程并不一定立即运行run方法,必须还要和其他线程竞争CPU时间
  • RUNNING 运行状态;线程获得CPU时间后才进入运行状态,开始执行run方法
  • BLOCKED 阻塞状态;线程运行过程中会有各种原因来进入阻塞状态,如:调用sleep方法进入休眠;在IO操作中被阻塞;试图得到一个锁,该锁正被其他线程持有;等待某个触发条件.阻塞状态的线程此时没有结束,暂时让出CPU时间给其他线程.
  • DEAD 死亡状态;有两个原因导致线程死亡:第一是run方法正常退出自然死亡;第二是一个未捕获的异常终止了run方法使线程死亡.

为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法,如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的,或者线程死亡了,则返回false。

二、具体创建方式

1.继承Thread类

package com.xingli.threadDemo;

/**
 *@ClassName MyThead
 *@Description 线程实现的方式第一种:继承thread类
 *@Author William
 *@Date 2019/8/6 11:44
 *@Version 1.0
 */
public class MyTheadTest {
    public static void main(String[] args) {
        //设置线程名字
        Thread.currentThread().setName("主线程:");
        MyThread myThread = new MyThread();
        myThread.setName("子线程:");
        //开启子线程
        myThread.start();
        //主线程
        for(int i = 0;i<5;i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}
/**
 *@description: 创建MyThread继承Thread类
 * @author: William
 * @date 2019/8/6 11:46
 */
class MyThread extends Thread{
    //重写Thread的run方法
    @Override
    public void run() {
        for (int i = 0; i <5 ; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

2.实现Runnable接口

package com.xingli.threadDemo;

/**
 *@ClassName MyRunnableTest
 *@Description 多线程实现的第二种方式,实现runnable接口
 *@Author William
 *@Date 2019/8/6 11:51
 *@Version 1.0
 */
public class MyRunnableTest {
    public static void main(String[] args) {
        //设置线程名称
        Thread.currentThread().setName("主线程:");
        Thread t = new Thread(new MyRunnable());
        t.setName("子线程:");
        //开启子线程
        t.start();
        for(int i = 0; i <5;i++){
            System.out.println(Thread.currentThread().getName()+":"+ i);
        }
    }
}

/**
 *@description: 创建MyRunnable实现Runnable接口
 * @author: William
 * @date 2019/8/6 11:52
 */
class MyRunnable implements Runnable {
    //重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() +":"+ i);
        }
    }
}

3.实现Callable接口

package com.xingli.threadDemo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 *@ClassName MyCallableTest
 *@Description 多线程实现的第三种方式,实现callable接口
 *@Author William
 *@Date 2019/8/6 12:03
 *@Version 1.0
 */
public class MyCallableTest {
    public static void main(String[] args) {
        //执行Callable 方式,需要FutureTask 实现实现,用于接收运算结果
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable(100));
        new Thread(futureTask).start();
        FutureTask<Integer> futureTask2 = new FutureTask<Integer>(new MyCallable(99));
        new Thread(futureTask2).start();
        //接收线程运算后的结果,这边有一个要注意的地方,FutureTask获取返回值会阻塞主线程,如果获取不到结果主线程下面的方法不会执行
        try {
            Integer sum = futureTask.get();
            System.out.println(sum);
            Integer sum2 = futureTask2.get();
            System.out.println(sum2);
            for (int i = 0; i < 5; i++) {
                System.out.println("主线程结果===");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

/**
 *@description: 创建MyCallable类实现Callable接口
 * @author: William
 * @date 2019/8/6 12:42
 */
class MyCallable implements Callable<Integer> {

    private Integer num ;
    /**
     *@description: 构造方法,让调用方传递一个int类型的数字过来
     * @param num     用户传递数字
     * @author: William
     * @date 2019/8/6 12:08
     */
    public MyCallable(Integer num){
        this.num =num;
    }
    //从写call方法,让方法返回用户传递值%3的结果
    @Override
    public Integer call() throws Exception {
        if(num == null || num<=0){
            return null;
        }
        return num%3;
    }
}

4.线程池创建

package com.xingli.threadDemo;

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

/**
 *@ClassName MyThreadPoolTest
 *@Description 多线程实现的第三种方式,实现callable接口
 *@Author William
 *@Date 2019/8/6 12:41
 *@Version 1.0
 */
public class MyThreadPoolTest {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPool threadPool = new ThreadPool();
        for(int i =0;i<5;i++){
            //为线程池分配任务
            executorService.submit(threadPool);
        }
        //关闭线程池
        executorService.shutdown();
    }
}

class ThreadPool implements Runnable {
    @Override
    public void run() {
        for(int i = 0 ;i<5;i++){
            System.out.println(Thread.currentThread().getName()+ ":" + i);
        }
    }
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/97044.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!