java 创建线程_Java多线程之通过继承Thread来创建线程并且调试代码

  昨天提到Java中创建线程时的方法,实现Runnable接口来创建线程。代码中在start()方法中,会先有一个判断,如下:

  if (thread == null) {

    System.out.println("thread starting" + threadName);

    thread = new Thread(this, threadName);

    thread.start();

 }

对于这段代码,怎么理解呢,为什么要有这个判断呢?

其实这里不是判断这个线程是否为空,而是线程是否在运行。如果线程是在运行的,你就不能去start 好比你在开车,车停了可以启动,如果车已经在开动中,你怎么启动呢?只能等车停下来再去启动。这不仅是校验线程,更是查看状态。这里默认的是如果线程在运行中,不做任何操作。

目前我的状态可能和开始新学Java的同学很像,就是写不出来代码,能看懂别人的,如果照着写是没有问题的。这时候就需要我们多写多想多思考。

这里我们也看下接口Runnable的内容:

@FunctionalInterfacepublic interface Runnable {/**     * When an object implementing interface Runnable is used     * to create a thread, starting the thread causes the object's     * run method to be called in that separately executing     * thread.     *      * The general contract of the method run is that it may     * take any action whatsoever.     *     * @see     java.lang.Thread#run()     */    public abstract void run();

我们在看下run()方法的源代码:

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

下面接着说通过继承Thread类方法来创建线程:

public class ThreadDemo extends Thread {
    private Thread thread; //创建一个线程thread
    private String threadName; //创建线程对应的名称为 threadName
    //调用有参的构造函数,主要是通过构造函数,将对象实例化时的threadName传参进来
    public ThreadDemo(String threadName){
        threadName = this.threadName;
        System.out.println("creating" + threadName);
    }
    //需要重写run()方法
    @Override
    public void run() {
        System.out.println("Running" + threadName);
        super.run();
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + " , " + i);
                Thread.sleep(5); //如果使用sleep的方法,需要抛出异常
            }
        }catch (InterruptedException e){
            System.out.println("Thread: " + threadName + "interrrupted.");
        }
        System.out.println("Thread: " + threadName + "exiting.");
    }
    //开始写start()方法
    public void start(){
        if (thread == null){ //线程没有在运行
            System.out.println("Thread: " + threadName + "starting.");
            thread.start();
        }
    }
}

注释都写在代码中了,我们来运行一下。

发现报错了,提示如下:

creatingnull
Thread: nullstarting.
Exception in thread "main" java.lang.NullPointerException
    at WeekendTest.ThreadDemo.start(ThreadDemo.java:34)
    at WeekendTest.TestThreadDemo.main(TestThreadDemo.java:14)
Process finished with exit code 1

定为到出错的那一行,根据信息提示,类是空的,在start()方法中没有给thread赋值,那我们来赋值一下,看看结果

//开始写start()方法
    public void start(){
        if (thread == null){ //线程没有在运行
            System.out.println("Thread: " + threadName + "starting.");thread = new Thread(this,threadName); //给thread赋值,target就是当前的值
            thread.start();
        }
    }

我们再运行试下:

发现还是报错...

creatingnullException in thread "main"
Thread: nullstarting.
java.lang.NullPointerException: name cannot be null
    at java.lang.Thread.init(Thread.java:369)
    at java.lang.Thread.init(Thread.java:349)
    at java.lang.Thread.(Thread.java:551)
    at WeekendTest.ThreadDemo.start(ThreadDemo.java:35)
    at WeekendTest.TestThreadDemo.main(TestThreadDemo.java:14)
Process finished with exit code 1

提示threadName为空

这时候我们需要去查看下threadName赋值情况

看下类的实例化为对象时的参数是怎么传递过来的。

public ThreadDemo(String name){
        name = this.threadName;
        System.out.println("creating" + threadName);
    }

看下上面的值,threadName是定义的线程的名字。类实例化后带入的参数就到了String name里的name中。然后将name值传给threadName作为线程的名字。看看我们的代码是怎么实现的:

name = this.threadName;

这句代码的意思是,将该类线程的名字传给了类实例化带来的参数,是不是写反了?应该是将name传给threadName

我们来修改下代码,如下:

public ThreadDemo(String name){
        threadName = name;
        System.out.println("creating" + threadName);
    }

我们再运行下,看下结果:

creating1-Thread
Thread: 1-Threadstarting.
creating2-Thread
Thread: 2-Threadstarting.
Running1-Thread
Thread: 1-Thread , 4
Running2-Thread
Thread: 2-Thread , 4
Thread: 1-Thread , 3
Thread: 2-Thread , 3
Thread: 1-Thread , 2
Thread: 2-Thread , 2
Thread: 1-Thread , 1
Thread: 2-Thread , 1
Thread: 1-Threadexiting.
Thread: 2-Threadexiting.
Process finished with exit code 0

这样结果就对了,是不?

我们在调试之前,需要从idea的提示语中大概的知道是什么原因,根据代码提示行的意思来知道问题原因并修复。

打断点的地方一半就是提示出错的代码行:

899a6c58a8f15ff98050191629c525af.png

e1958dc2e0ebabcb93259784d852501c.png

debug后,发现这里的threadName = null

那就是出问题的地方了

好了,今天先到这里吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值