几张图片带你秒懂Java中线程创建的两种方式

 在对线程、多线程、进程、多进程的阐述之后,对自己的鼓励还是比较大的,因为在来到CSDN半年左右的时间,终于拿到了一次首页推荐的机会,但是自认为还是比较菜的,应该算是在各位前辈面前献丑了…,在后面的日子里自己也会倍加努力的,今天想继续分享一些线程相关的知识点,希望得到大家的批评指点,更希望可以帮助更多的伙伴们!

在这里插入图片描述

嘿嘿,拿出来献丑了

线程创建的两种方式

1.继承Thread类的方式

单个线程的创建:

 Java中的线程有一个专门的类——Thread,在Thread类中会提供一个run方法,因此用户在使用线程的时候,主要是采用继承Thread加覆盖run方法的形式来实现所需的业务逻辑。
 在run方法里仅仅只做了一个对象的非空判断,new对象后调用Thread中的run方法而不去覆盖是没有意义的;

  /* What will be run. */
    private Runnable target;
    
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

在这里插入图片描述

多线程的创建:

 在主函数中调用start()方法时,旨在告诉主函数所有的线程都已经准备完毕,进而启动线程,需要CPU去给各个线程分配执行的时间片。因为main()函数时函数的起始位置,因此时间片最先在主线程,主线程时间片执行到期后,随机分配给其他线程。

方法 描述
void start() 使该线程开始执行; Java虚拟机调用此线程的run方法。
public class TestCreateThread {
    public static void main(String[] args){
        MyThread1 thread1 = new MyThread1();
        MyThread2 thread2 = new MyThread2();

        thread1.start();
        thread2.start();
        for (int i = 0; i < 50; i++) {
            System.out.println("Main: "+i);
        }

        System.out.println("程序执行结束!");
    }
}
class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("MyTread1:"+i);
        }
    }
}
class MyThread2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("MyTread2:"+i);
        }
    }
}

打印结果:
在这里插入图片描述

  • 分配时间片的对象是随机的,时间片的长度也是随机的;
  • 最有可能先执行完毕的main函数

2.实现Runnable接口的形式

Runnable是一个接口, 接口本身是一种能力,而Runnable的能力就是使程序的线程开始执行,这主要因为此接口里面有一个run()方法;因此任何一个线程,只要传入该接口实现类的实例对象为参数,那么,此线程就具备独立执行的能力;
Runnable接口应由任何类实现,其实例将由线程执行。 该类必须定义一个无参数的方法,称为run 。

  • Runnable接口源码
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
  • Thread类部分源码
     虽然Runnable参数传进来之后,经过几次方法的调用和传递,就做了一件事情:当使用Thread使用有参构造方法时,实际上就是把Runnable类型的对象,最后付给了它的实例变量,类似于构造函数的形式;
  /* What will be run. */
    private Runnable target;
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
	    init(g, target, name, stackSize, null, true);
    }
    private void init(ThreadGroup g, Runnable target, String name,
    			long stackSize,AccessControlContext acc,boolean inheritThreadLocals) {
		 //此处原则性筛除一些代码
    	this.target = target;
   }

 此时的Thread中的run方法中的判断,此时因Runnable参数的传入,满足了target != null的条件,因此调用 target.run();方法,这里就是接口的回调,回调Runnable中的run()方法;

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

单个线程的创建

在这里插入图片描述

多个线程的创建

public class TestRunnable {
    public static void main(String[] args){
        MyRunnable runnable = new MyRunnable();
        //分别创建两个线程,并传入runnable参数
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        //运行线程
        thread1.start();
        thread2.start();
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            //打印当前线程的名字和值
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

打印结果:
在这里插入图片描述

小结

  • 类比两种方式,方式二灵活性更强一些,尤其是多个线程执行相同的业务逻辑时,方式二的使用更具有合理性;
  • 线程的状态执行基本过程:
    在这里插入图片描述
发布了82 篇原创文章 · 获赞 124 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_44717317/article/details/104753454
今日推荐