多线程(线程的创建与常见方法的使用)

线程,作为程序执行的最小单元,能够让程序在同一时间内处理多个任务,避免因单任务阻塞而造成的资源浪费。无论是处理大量用户请求的服务器端应用,还是需要同时进行数据计算与 UI 交互的客户端程序,多线程都扮演着至关重要的角色。

一、线程的创建

在 Java 编程中,多线程是实现并发执行的重要手段,它能让程序同时处理多个任务,提升运行效率。以下将详细介绍 Java 中创建多线程的三种常用方式,包括它们的实现步骤、优缺点及适用场景。

1、通过继承Thread的方式实现

Thread 类是 Java 中用于线程操作的基础类,通过继承该类可以直接创建线程。

实现步骤

  1. 自定义一个类,继承 Thread 类。
  2. 重写 Thread 类中的 run () 方法,在该方法中编写线程要执行的任务代码。
  3. 创建自定义类的实例对象。
  4. 调用实例对象的 start () 方法启动线程(注意:不可直接调用 run () 方法,否则会当作普通方法执行,无法实现多线程并发)。
package org.example;

public class MyThread extends Thread{
    // 构造方法,用于设置线程名称
    public MyThread() {}
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        // 线程执行的任务:输出10条信息
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100); // 休眠100毫秒
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getName() + "hello" + i);
        }
    }
}

// 启动线程
public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread("线程1");
        MyThread thread2 = new MyThread("线程2");
        thread1.start();
        thread2.start();
    }
}

优点

  • 编程简单直接,可直接使用 Thread 类中的方法(如 getName () 获取线程名称)。

缺点

  • 扩展性较差,由于 Java 是单继承机制,继承了 Thread 类后就不能再继承其他类。

适用场景:简单的多线程任务,且不需要继承其他类的场景。

2、 通过Runnable 接口实现

Runnable 接口是 Java 中定义线程任务的接口,通过实现该接口可以更灵活地创建线程。

实现步骤

  1. 自定义一个类,实现 Runnable 接口。
  2. 重写 Runnable 接口中的 run () 方法,编写线程任务代码。
  3. 创建自定义类的实例对象(该对象表示线程要执行的任务)。
  4. 创建 Thread 类的实例对象,将自定义类的实例作为参数传入 Thread 的构造方法中。
  5. 调用 Thread 实例的 start () 方法启动线程。
package org.example;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        // 线程执行的任务:输出100条信息
        for (int i = 0; i < 100; i++) {
            Thread t = Thread.currentThread(); // 获取当前线程对象
            System.out.println(t.getName() + "hello" + i);
        }
    }
}

// 启动线程
public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable, "线程1");
        Thread thread2 = new Thread(myRunnable, "线程2");
        thread1.start();
        thread2.start();
    }
}

优点

  • 扩展性强,实现 Runnable 接口的同时还可以继承其他类。
  • 适合多个线程共享同一个任务资源的场景。

缺点

  • 编程相对复杂,不能直接使用 Thread 类中的方法,需通过 Thread.currentThread () 获取当前线程对象后再调用相关方法。

适用场景:多线程共享资源的场景,或需要继承其他类的场景。

3、通过 Callable 接口结合 FutureTask 类实现

Callable 接口与 Runnable 接口类似,但它可以获取线程执行的返回结果,适用于需要获取线程执行结果的场景。

实现步骤

  1. 自定义一个类,实现 Callable 接口(需指定返回值类型)。
  2. 重写 Callable 接口中的 call () 方法,编写线程任务代码,并返回执行结果。
  3. 创建自定义类的实例对象(表示线程任务)。
  4. 创建 FutureTask 类的实例对象,将 Callable 实例作为参数传入(用于管理线程执行结果)。
  5. 创建 Thread 类的实例对象,将 FutureTask 实例作为参数传入。
  6. 调用 Thread 实例的 start () 方法启动线程。
  7. 调用 FutureTask 实例的 get () 方法获取线程执行的返回结果
package org.example;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 线程执行的任务:计算1到100的和
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}

// 启动线程并获取结果
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        Integer result = futureTask.get(); // 获取线程执行结果
        System.out.println(result);
    }
}

优点

  • 可以获取线程执行的返回结果,功能更强大。
  • 扩展性强,实现 Callable 接口的同时可以继承其他类。

缺点

  • 编程最为复杂,需要结合 FutureTask 类来管理返回结果。

适用场景:需要获取线程执行结果的场景,如多线程计算并汇总结果的任务。

二、线程的常见方法

线程的方法是控制线程行为的关键,掌握这些方法能让我们更好地管理线程的执行顺序、状态等。以下将详细介绍 Java 线程中常见的方法及其使用场景。

线程的常见方法如下:

  • 1、getName()  返回该线程的名称
  • 2、setName(String name) 设置线程的名字
  • 3、static Thread currentThread() 获取当前线程对象
  • 4、static void sleep(long time) 让线程休眠的时间,单位是毫秒
  • 5、setPriority(int newPriority) 设置线程的优先级
  •  6、final int getPriority()获取线程的优先级
  • 7、final void setDaemon(boolean on)
  • 8、static void yield()出让线程/礼让线程
  • 9、final void join()插入线程/插队线程

1、线程名称相关方法

  • String getName():返回当前线程的名称。若未手动设置,线程会有默认名称(格式为 “Thread-x”,x 为数字)。
  • void setName(String name):设置线程的名称,也可通过线程的构造方法设置名称。
// 通过构造方法设置名称
MyThread thread1 = new MyThread("飞机");
// 通过setName()方法设置名称
MyThread thread2 = new MyThread();
thread2.setName("坦克");

2、获取当前线程对象

  • static Thread currentThread():获取当前正在执行的线程对象。在 main 方法中调用时,获取的是 main 线程对象。
// 在Runnable实现类的run()方法中获取当前线程
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println(t.getName());
    }
}

3、线程休眠

  • static void sleep(long time):让当前线程休眠指定的时间(单位为毫秒),休眠期间线程会释放 CPU 资源,时间结束后重新参与 CPU 调度。
@Override
public void run() {
    for (int i = 0; i < 10; i++) {
        try {
            Thread.sleep(100); // 休眠100毫秒
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(getName() + "hello" + i);
    }
}

4、线程优先级

  • setPriority(int newPriority):设置线程的优先级,优先级范围为 1-10,默认优先级为 5,优先级越高,线程获取 CPU 资源的概率越大(但不保证一定先执行)。
  • final int getPriority():获取线程的优先级。
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable, "飞机");
Thread thread2 = new Thread(myRunnable, "坦克");
thread1.setPriority(10); // 设置最高优先级
thread2.setPriority(1); // 设置最低优先级
thread1.start();
thread2.start();

5、守护线程

  • final void setDaemon(boolean on):设置线程为守护线程(当参数为 true 时)。守护线程是为其他线程服务的,当所有非守护线程执行完毕后,守护线程会自动结束。
MyThread thread1 = new MyThread("飞机"); // 非守护线程
MyThread2 thread2 = new MyThread2("坦克"); // 守护线程
thread2.setDaemon(true);
thread1.start();
thread2.start(); // 当thread1执行完毕后,thread2会陆续结束

6、线程礼让

  • public static void yield():出让当前线程的 CPU 执行权,让其他线程有机会执行,但当前线程仍可能再次获取 CPU 资源。
@Override
public void run() {
    for (int i = 0; i < 10; i++) {
        System.out.println(getName() + "hello" + i);
        Thread.yield(); // 出让CPU执行权
    }
}

7、线程插队

  • public final void join():让调用该方法的线程插入到当前线程之前执行,当前线程会等待插入的线程执行完毕后再继续执行。
public class Main {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread1 = new MyThread("飞机");
        thread1.start();
        thread1.join(); // 让thread1插入到main线程之前执行
        // main线程会等待thread1执行完毕后再执行以下循环
        for (int i = 0; i < 10; i++) {
            System.out.println("main" + i);
        }
    }
}

通过上述方法的灵活使用,我们可以有效地控制线程的执行流程,实现多线程之间的协作与同步,满足不同场景下的并发需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值