[Java 并发编程] 6. 创建和开始Java线程

tech2024-11-04  32

文章目录

前言一、创建和开始线程二、Thread 子类三、实现 Runnable 接口3.1 Java 类实现 Runnable 接口3.2 Java 匿名类实现 Runnable 接口3.3 Lambda 表达式实现 Runnable 接口3.4 开启一个实现了 Runnable 接口的线程 四、使用哪种方式创建线程更好?五、常见陷阱:调用 run() 代替 start()六、 线程名(Thread Names)七、Thread.currentThread()八、暂停线程九、停止一个线程


前言

一个Java线程就像一个可以执行你的Java代码的虚拟CPU。

当Java虚拟机创建的主线程开始执行main方法时,你的Java应用程序启动,在你的Java应用程序里面你可以创建和开始你自定义的线程。

Java 线程都是对象,就像其他的Java对象一样,线程对象都是 java.lang.Tread 的实例或者其子类的实例。


一、创建和开始线程

你可以像这样创建一个线程对象:

Thread myThread = new Thread();

你可以像这样开始一个线程:

myThread.start();

创建线程的几种方式:

继承 java.lang.Thread 类并重写 run() 方法。实现 java.lang.Runnable 接口并重写 run() 方法。实现 java.util.concurrent.Callable 接口并重写 call() 方法。

二、Thread 子类

继承 java.lang.Thread 类并重写 run() 方法

//Thread子类 public class MyThread extends Thread { public void run(){ System.out.println("MyThread running"); } } //main方法 public static void main(String[] args){ MyThread myThread = new MyThread(); myThread.start(); }

start() 方法不会等线程执行完 run()方法,run() 方法将会由不同的线程执行。


三、实现 Runnable 接口

第二种创建线程的方式是实现 java.lang.Runnable 接口并重写该接口的 run() 方法。一个 Java 对象实现 Runnable 接口 可以被Java Thread 类执行。

Runnable 接口由 JDK 提供,仅有一个 run 方法,是一个函数式接口。源码如下:

@FunctionalInterface public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }

实现 Runnable 的方式有3种:

创建一个 Java 类实现 Runnable 接口创建一个 Java 匿名类实现 Runnable 接口使用 Java 8 Lambda 表达式实现 Runnable 接口

3.1 Java 类实现 Runnable 接口

例如:

public class MyRunnable implements Runnable { public void run(){ System.out.println("MyRunnable running"); } }

3.2 Java 匿名类实现 Runnable 接口

例如:

Runnable myRunnable = new Runnable(){ public void run(){ System.out.println("Runnable running"); } }

3.3 Lambda 表达式实现 Runnable 接口

例如:

Runnable runnable = () -> { System.out.println("Lambda Runnable running"); };

3.4 开启一个实现了 Runnable 接口的线程

java.lang.Thread的包含传入一个Runnable接口的构造函数。

public static void main(String[] args) { //or an anonymous class, or lambda... Runnable runnable = new MyRunnable(); //executed by a thread Thread thread = new Thread(runnable); thread.start(); }

四、使用哪种方式创建线程更好?

关于继承Thread和实现Runnable接口,没有明确的规定用哪种方式创建线程更好,两种方式都可以让线程运行。我更倾向于使用实现Runnable接口的方式,后面我还们会了解到另外一种创建线程的方式,通过线程池创建线程的方式更加合理。


五、常见陷阱:调用 run() 代替 start()

通过调用start(),程序会告诉 CPU 线程已准备就绪,等待CPU执行 run() 方法。若直接调用 run() 方法则不会开启一个新的线程去执行 run() 方法,而是在原来的线程中去执行 run() 方法,所以当我们需要一个新的线程去执行 run() 方法中的代码时,应该调用 start() 方法启动一个线程,而不是直接调用 run() 方法。


六、 线程名(Thread Names)

创建线程的时候可以指定线程名称,详见 java.lang.Thread API

public static void main(String[] args) { Runnable myRunnable = () -> System.out.println("Thread name is " + Thread.currantThread().getName()); new Thread(myRunnable, "Thread One").start(); } console out: Thread name is Thread One

七、Thread.currentThread()

通过 Thread.currentThread() 获取当前正在执行的线程对象。

Thread currentThread = Thread.currentThread();

八、暂停线程

可以通过 Thread.sheep() 让线程睡眠指定毫秒数。这里不建议使用 thread.suspend() 方法,该方法和 Thread 类的 resume()、stop()、destroy() 都是 JDK 标注废弃方法。

try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); }

注意: Thread.sheep() 方法不会释放CPU资源,如果设置锁的话也不会释放锁资源,只是让线程睡眠指定毫秒数。与 Object 类的 wait() 方法不同, wait() 方法主要用于线程通信,且 wait() 方法会释放锁资源。


九、停止一个线程

不建议使用 Thread 类提供的 stop() 方法去停止一个线程,stop() 方法会暴力停止一个线程,对程序不友好,可以通过更友好的方式停止一个线程。

请看示例:

public class MyRunnable implements Runnable { private boolean doStop = false; public synchronized void doStop() { this.doStop = true; } private synchronized boolean keepRunning() { return this.doStop == false; } @Override public void run() { while(keepRunning()) { // keep doing what this thread should do. System.out.println("Running"); try { Thread.sleep(3L * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } } } }

请注意 doStop() 方法和 keepRunning() 方法使用了 synchronized 关键字,后面会详细讲解 synchronized 关键字的作用,这里不做过多描述。

public class MyRunnableMain { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); try { Thread.sleep(10L * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } myRunnable.doStop(); } }

上面示例通过设置一个标识,主线程里面启动子线程,然后主线程睡眠10秒钟后调用 doStop() 方法,实现在主线程中停止子线程的运行。

最新回复(0)