juc07 创建线程

2023-10-20 10:11:26 浏览数 (2)

创建线程

JAVA中线程被封装成Thread对象。JDK API中有对Thread的说明,连创建方式都有。 自定义线程有两种方式:

  1. 继承Thread
  2. 实现Runable接口

从打印结果是否是不同线程运行来验证多线程执行。 主线程代码在main方法中,自定义线程方法代码在run方法中。

两种创建方式的区别:

  1. Thread 的代码是存在子类当中;
  2. Runable方式的代码是的实现接口的子类当中,还避免了单继承的问题。

一、继承 Thread 方式

这种方式最简单,需要三个步骤:

  1. 继承 Thread 类
  2. 重写 run 方法,run方法要看成一个入口点。
  3. 调用 start 方法来执行自定义线程

实现代码:

代码语言:javascript复制
public class TestThread extends Thread {
  //1.继承Thread
  @Override
  public void run() {

    //2.重写run方法
    //super.run();
    for (int i = 0; i < 100; i  ) {
      System.out.println("run: "  i);
    }
  }

  public static void main(String[] args) {
    //3.执行start线程
    TestThread testThread = new TestThread();
    testThread.start();
    for (int i = 0; i < 100; i  ) {
      System.out.println("main: "  i);
    }
  }
}

结果 会交替打印 run 和 main 证明CPU执行线程时是交替进行的。而且这种交替是随机性的。

说明:run方法中写上自定义线程要执行的程序,而调用 start 才是真正表示开始执行这条自定义线程。 理解: main是程序默认线程入口,run 是自定义程序入口,和 main 等价。 但是 main 是程序开启的,run 是由用户开启的。

注意事项

  1. 注意this

如果继承自Thread类,可以直接使用this关键字来调用Thread类中的方法,如getName方法,因为是继承所以可以直接使用方法。

  1. 注意super

继承Thread后,也可以直接调用父类的方法给自己用,而不需要.currentThread.方法。 如super(name); 直接调用构造方法重命名线程。

二、Runable 方式

这种方式业务类必须实现Runnable接口,并将业务类所创建的对象传入 Thread 对角中去。 由于对象只有一份,所以多个 Thread 对象操作的是同一个对象,所以就会产生共享数据的问题,即,不安全问题的产生。

代码实现

代码语言:javascript复制
public class TestSun {
  public static void main(String[] args) {
    TestClass c = new TestClass();
    TestClass d = new TestClass();

    Thread t1 = new Thread(c);        //TestClass 必须实现Runnable的run方法才能使用这种方式。
    Thread t2 = new Thread(d);
    t1.start();
    t2.start();
  }
}

// 继承 Runnable
class TestClass implements Runnable {
  public void run() {
    System.out.println("子类重写run方法");
  }
}

多写一个例子:

代码语言:javascript复制
public class TestSun implements Runnable {
  public static void main(String[] args) {
    TestSun testSun = new TestSun();
    Thread t = new Thread(testSun);
    t.start();
  }

  public void run() {
    //do 
  }
}

理解:例用实现Runnable还有一个好处就是,我不同的类,我可以有不同的run实现方法,

Runable 共享资源问题

下面代码的执行结果是:输出 50次。如果使用继承Thread的方式的话,会被执行200次。 原就是就因为 Test 对象实际上被所有线程所共享,所有线程所操作的时同一个对象。 如果使用Thread方式,给变量i设为静态也可以做到执行50次,但是静态的生命周期太长了,不推荐。 这个例子为了说明 Thread 和 Runable 的区别。 而为什么 Thread 对执行多次,是因为继承的Thread 后,每new 一次,就是创建的一个新对象,每个对象都是一分独立的副本,并不是同一个对象。

代码语言:javascript复制
package com.liukai.thread;

public class TestThread2 {
  public static void main(String[] args) {
    Test test = new Test();
    Thread t1 = new Thread(test);
    Thread t2 = new Thread(test);
    jhread t3 = new Thread(test);
    t1.start();
    t2.start();
    t3.start();
  }

}

class Test implements Runnable {
  boolean flag = true;
  int i = 50;

  public void run() {
    while (flag) {
      System.out.println(Thread.currentThread().getName()   "---"   i--);
      if (i <= 0) {
        flag = false;
      }
    }

  }

}

区别

runnable 和 继承Thread 方式的区别 这种非常重要的概念,一定要明白。关系到线程的执行方式。

  1. 继承Thread类方式:线程到码存放在Thread子类的run方法中。即继承了Thread类的自定义线程类的run方法中。
  2. 实现Runnable接口方式:线程代码存在接口的子类的run方法中。注意是接口的子类的run方法中,不是实现类的run方法中。

第2种方式最常用。 优点:

  1. 避免单继承的局限性。
  2. 多个业务代码可以有不同的代码存放区。

0 人点赞