首页 > 其他分享 >多线程的创建方式

多线程的创建方式

时间:2024-07-26 09:24:24浏览次数:13  
标签:null Thread 方式 创建 void Runnable 线程 多线程 public

线程的创建方式

1:通过继承Thread类创建一个线程类.子类重写Thread的run方法即可.

public class ThreadTwoTest extends Thread{

    public static void main(String[] args) {
        ThreadTwoTest threadTwoTest = new ThreadTwoTest();
        threadTwoTest.start();
    }

    @Override
    public void run() {
        System.out.println("我实现了Thread,我是一个线程子类.");
    }
}

 2:通过继承Runnable接口创建一个线程.

public class ThreadThreeTest implements Runnable {

  public static void main(String[] args) {

        ThreadThreeTest threadThreeTest = new ThreadThreeTest();
        Thread thread = new Thread(threadThreeTest);
        thread.start();
    }

    @Override
    public void run() {
        System.out.println("我是通过实现Runnable接口实现的一个线程类.");
    }
}

3:使用Cllable接口创建线程,泛型可以指定返回的类型.

public class ThreadCallableTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ReturnableTask returnableTask = new ReturnableTask();
        FutureTask<String> futureTask = new FutureTask<String>(returnableTask);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());
    }

    static class ReturnableTask implements Callable<String> {

        @Override
        public String call() throws Exception {
            return "我实现了callable接口创建了线程,拿到了返回结果";
        }
    }
}

4:通过线程池创建线程.

public class ThreadPoolTest {
    public static void main(String[] args) {
        //定长线程池.
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        //缓存线程池.
        ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
        //定时线程池.
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
        //单例线程池.
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
    }
}

通过了解线程的创建方式可以看到最基础的还是Thread这个类.它的结构如下.

线程ID属性: private long tid
获取线程Id方法: public long getId()
线程名称属性: private String name
获取线程名称方法一: public final String getName()
设置线程名称方法二: public final void setName(String name)
构造方法设置名称方法二: Thread(String threadName)
线程优先级属性: private int priority
获取线程优先级方法一: public int getPriority()
设置线程优先级方法二: public final void setPriority(int priority)
是否为守护线程属性: private boolean daemon =false
设置为守护线程方法: public final void setDaemon(boolean on)
线程的状态属性: private int threadStatus
获取线程状态方法: public Thread.State getState() 
线程状态属性:  NEW(新建)
属性: RUNNABLE(就绪运行)
属性: BLOCKED(阻塞)
属性: WAITING(等待)
属性: TIMED_WAITING(计时等待)
属性:  TERMINATED(结束)
线程的启动方法: public void start()
线程的运行方法: public void run()
获取当前线程方法: public staic Thread currentThread()

表格里总结了一些比较主要的属性和方法,还有其他一些重要的属性,具体可以进入源码在细细品味.

public class ThreadOneTest {

    public static void main(String[] args) {
        Thread thread = new Thread();
        //线程的名字.
        System.out.println("线程的名字--" + thread.getName());
        //线程的id.
        System.out.println("线程的id--" + thread.getId());
        //线程状态.
        System.out.println("线程状态--" + thread.getState());
        //线程的优先级.
        System.out.println("线程的优先级--" + thread.getPriority());
        thread.start();
    }

}

Thread的创建方式.

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

空参构造方法.

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

传入一个Runnable实例.

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

传入线程组和Runnable实例.

public Thread(String name) {
        init(null, null, name, 0);
    }

指定一个线程名称.

 public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }

传入线程组和指定线程名称.

 public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

传入Runnable实例和指定线程名称.

public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

传入线程组和Runnable实例和指定线程名称.

了解了Thread类的构造方法,会发现核心应该是这个Runnable接口.

public class Thread implements Runnable{
}

而且Thread类实现了这个接口.这个接口有一个方法,

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

看到里的话.是不是就清楚了Thread和Runnable这两种创建线程的联系.java支持类的单继承,接口是多实现.Runnable接口增强了创建线程的灵活性.拓展性也强了.(当然很官话,还是忍不住想要分享一下自己的一个感觉,虽然不一定对,但是还是很开心有所收获).

从run方法可以看出来,不支持返回值.所以就引入了Callable接口.

@FunctionalInterface
public interface Callable<V> {
  
    V call() throws Exception;
}

它的返回值是一个泛型.看到这里返回头看下Thread的start()方法做了什么.

 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

重点在这里 this.target = target;这个target就是我们传入的Runnable实例.

 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

最后执行的就是Runnable接口的run方法,也就是我们实现的那个方法.所以那么问题就来了,callable是怎么进行的呢.一个实现了RunnableFuture接口的FutureTask<v>类就出现了.启到一个承上启下.

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

看到这个是不是一下子就恍然大悟,是不是有一种适配器的感觉油然而生.

 public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
Callable<V> c = callable;这个实例就是实现了callable接口的对象.里面最终会执行result = c.call();最后会把result值放到outcome这个属性里.
 protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }

最后就可以通过FutureTask<v>对象的get方法取到线程的返回值.

关于线程池就等后面在具体介绍吧.因为我是第一次写技术博客,好多东西可能并不是那么完美.有不足的地方希望大家可以多多指教.不管什么时候,大家都是进步的.我也是一样,既然选择开始,那就坚持这个开始.

标签:null,Thread,方式,创建,void,Runnable,线程,多线程,public
From: https://blog.csdn.net/m0_68082638/article/details/140583752

相关文章

  • DevExtreme框架由于数据量太大,加载太慢,采用分页方式进行处理(基本上所有的操作都从客户
    首先我们需要引入官方的一个函数:importCustomStorefrom'devextreme/data/custom_store';我们需要通过这个函数去处理交互数据 先放个图: 上图中跟分页有关的属性分别是:1.:data-source="store",这个是存放数据源用的,需要用到我们上面的CustomStore函数,2.:remote-oper......
  • Numpythonic 方式从所需的时间步长和窗口大小构造窗口向量
    给定参数timestep=2window_size=3我已经展平了大小为9的时间序列向量。内容是:arr=np.array([1,2,3,4,5,6,7,8,9])如何使用这些参数重塑/构造窗口时间序列?我希望输出具有形状unknown,window_size)所以,它的输出将是这样的矩阵:windowed_arr=np......
  • 双 for 循环的 Pythonic 方式
    我有以下代码:importnumpyasnpepsilon=np.array([[0.,0.00172667,0.00071437,0.00091779,0.00154501],[0.00128983,0.,0.00028139,0.00215905,0.00094862],[0.00035811,0.00018714,0.,0.00029365,0.00036993......
  • 【PostgreSQL教程】PostgreSQL 创建数据库
    博主介绍:✌全网粉丝20W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。感兴趣的可以先......
  • 量化基本知识点梳理-三种量化方式和量化框架以及trt
    这一文档介绍些基础概念吧,权当做一个阶段整理,后面也会慢慢完善。1.量化分类:根据谷歌量化白皮书中定义,分为PTQ和QAT两种,而PTQ又包括两种。3种量化方式:QAT,PTQDynamic,PTQStatic。1)量化感知训练(QuantAwareTraining,QAT):量化训练让模型感知量化运算对模型精度带来的......
  • 记录|C#+winform创建扁平化风格界面
    本项目的C#内容是自己跟做的,自己做的内容已经打包,可以通过自己跟做写的Dashboard界面,C#下的winform模式下载获得,但是需要花费3个积分目录前言一、左边设置和步骤界面步骤Step1.Step2.Step3.Step4Step5二、右边属性和步骤属性设置步骤Step1.Step2.Step3.三、最终效......
  • django_创建菜单(实现整个项目的框架,调包)
    文章目录前言代码仓库地址在线演示网址启动网站的时候出现错误渲染路径的一些说明文件结构网页显示一条错误路由顺序js打包出现问题的代码函数没有起作用关于进度开发细节显示不了图片梳理一下函数调用的流程修改一些宽度参数classjs里面的一些细节让三个按钮可以点击设......
  • 创建vue 2的时候出bug我看不懂,求大佬们帮帮忙,还在学习阶段
    VueCLIv5.0.8?Pleasepickapreset:Default([Vue2]babel,eslint)VueCLIv5.0.8✨ CreatingprojectinF:\aaa\eee\aaa.......
  • 多线程补充(上)
    线程安全问题首先,什么是线程安全问题呢?线程安全问题指的是,多个线程同时操作同一个共享资源的时候,可能会出现业务安全问题。场景:小明和小红是一对夫妻,他们有一个共享账户,余额是10万元,小红和小明同时来取钱,并且2人各自都在取钱10万元,可能出现什么问题呢?小明和小红假设都是......
  • 多线程创建方式和常用方法
    线程其实是程序中的一条执行路径。怎样的程序才是多线程程序呢?可以同时有很多人一起进入的网站,而且每一个人互不影响。比如百度网盘,可以同时下载或者上传多个文件。这些程序中其实就有多条执行路径,每一条执行执行路径就是一条线程,所以这样的程序就是多线程程序。Java提供了几......