1、多线程代码运行的特点

  1. 每一条线程,如果抢不到CPU的执行权,就执行不了代码。
  2. 只有抢到了CPU的执行权,才能执行run方法里面的代码。
  3. 在执行代码的过程中,随时都有可能被另外的线程抢走CPU的执行权。
  4. 如果我们同时开启了多条线程,在执行的时候,结果有可能每次都不一样,是随机的。

2、创建线程方式一(继承方式)

​ Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建启动多线程的步骤如下:

​ 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。创建Thread子类的实例,即创建了线程对象调用线程对象的start()方法来启动该线程。

​ 测试类:

public class Test {
    public static void main(String[] args) {
        //1.创建线程的对象
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        //2.开启线程,让线程跑起来
        t1.start();
        t2.start();

        //并没有开启线程
        //普通的方法调用
        //是运行在虚拟机中的main线程中的。
        //t1.run();

        //特点:
        //在Java中,线程启动之后。
        //在每一个时刻,到底是那条线程执行,我们是无法控制的。
        //随机性。
        //当线程启动之后,多条线程,都在抢夺CPU的执行权。
        //谁抢到了CPU,那么就执行哪条线程。
    }
}

自定义线程类:

public class MyThread extends Thread{

//因为run方法里面的代码,就是线程开启之后,要运行的代码
@Override
public void run() {
    for (int i = 1; i <= 100; i++) {
        System.out.println(getName() + "@" + i);
        }
    }
}

3、创建线程的方式二(实现方式)

采用java.lang.Runnable也是非常常见的一种,只需要重写run方法即可。

步骤如下:

  1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
  3. 调用线程对象的start()方法来启动线程。

代码如下:

public class MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(i);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //1.创建的是线程要执行的参数对象
        //创建了一个参数对象
        MyRunnable mr1 = new MyRunnable();
        //又创建了一个参数对象
        MyRunnable mr2 = new MyRunnable();

        //2.创建线程对象
        //两条线程,各自跑各自的
        //线程一,跑参数一
        Thread t1 = new Thread(mr1);
        //线程二,跑参数二
        Thread t2 = new Thread(mr2);

        t1.start();
        t2.start();

    }
}

​ 通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个执行目标。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。

​ 在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码。

​ 实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。

tips:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。

总结:

Thread和Runnable的区别

实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源。
  2. 可以避免java中的单继承的局限性。
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
  4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

4、线程的姓名

第一种创建多线程的方式中。

​ 利用set方法设置姓名

​ 利用构造方法设置姓名

​ 利用get方法获取姓名

代码示例:

public class Test {
    public static void main(String[] args) {
        //子类不能继承父类的构造方法
        //但是可以通过super进行调用
        //1.创建线程的对象
        MyThread t1 = new MyThread("火车");
        MyThread t2 = new MyThread("飞机");

        //细节
        //起名字,要在创建对象之后,开启线程之前
        //t1.setName("火车");
        //t2.setName("飞机");

        //2.开启线程,让线程跑起来
        t1.start();
        t2.start();
      
    }
}

public class MyThread extends Thread{
    //此时我们没有写构造,jvm会加一个无参构造
    public MyThread() {
    }
    public MyThread(String name) {
        super(name);
    }

    //因为run方法里面的代码,就是线程开启之后,要运行的代码
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //此时getName是获取当前线程的姓名
            System.out.println(getName() + "@" + i);
        }
    }
}

第二种创建多线程的方式中。

代码示例:

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //Thread.currentThread(); 哪条线程执行到这行代码,此时获取的就是当前线程的对象
            System.out.println(Thread.currentThread().getName() + "@" +i);
        }
    }
}


public class Test {
    public static void main(String[] args) {
        //1.创建的是线程要执行的参数对象
        //创建了一个参数对象
        MyRunnable mr1 = new MyRunnable();
        //又创建了一个参数对象
        MyRunnable mr2 = new MyRunnable();

        //2.创建线程对象
        //两条线程,各自跑各自的
        //线程一,跑参数一
        Thread t1 = new Thread(mr1,"线程A");
        //线程二,跑参数二
        Thread t2 = new Thread(mr2,"线程B");
        
        t1.start();
        t2.start();
    }
}
版权属于:it小离

本文链接: https://www.itxiaoli.cn/archives/thread.html

版权声明:本站文章采用 署名-非商业性使用-相同方式共享 4.0

最后修改:2022 年 03 月 25 日 07 : 00 PM
如果觉得我的文章对你有用,请随意赞赏