85- 多线程中常见的成员方法

 一、方法

  1. start():启动线程。调用start()方法后,线程会被纳入到线程调度器中,等待调度执行。
  2. run():线程的执行逻辑。需要重写该方法,在其中编写线程需要执行的任务逻辑。
  3. join():等待线程终止。调用该方法会使当前线程等待被调用的线程执行完毕再继续进行。
  4. sleep(long millis):线程休眠。使当前线程暂停执行指定的时间(以毫秒为单位),让出CPU资源。
  5. yield():线程让步。暂停当前正在执行的线程,让其他具有相同优先级的线程有机会执行。
  6. interrupt():中断线程。向目标线程发送中断信号,该信号可以由目标线程的代码检测到并进行相应的处理。
  7. isInterrupted():检查线程是否被中断。判断当前线程是否处于中断状态。
  8. setPriority(int priority):设置线程优先级。用于设置线程的执行优先级,指定取值范围为1-10(10为最高优先级)。
  9. getState():获取线程状态。返回当前线程的状态,如NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED等。
  10. wait()、notify()和notifyAll():用于线程之间的通信。wait()使当前线程进入等待状态,notify()唤醒一个等待中的线程,notifyAll()唤醒所有等待中的线程。
  11. synchronized关键字:线程同步。使用synchronized关键字修饰方法或代码块,实现对共享资源的互斥访问,防止多个线程同时修改数据。

二、线程的优先级:

线程的优先级是指在多线程环境下,操作系统对线程调度的一种依据,用于确定线程获得 CPU 执行时间的相对权重。Java中线程的优先级范围是1-10,其中1表示最低优先级,10表示最高优先级。

线程的优先级可以通过setPriority(int priority)方法进行设置,也可以使用getPriority()方法获取当前线程的优先级。

需要注意的是,线程优先级只是给调度器一个提示,无法确保高优先级的线程一定会先执行。操作系统的调度算法会根据不同的实现和策略进行线程调度,因此不能过度依赖线程的优先级来编写可靠的程序。

优先级较高的线程在竞争CPU资源时可能会更容易被调度执行,但并不保证一定会获得更多的执行时间。实际上,线程的调度顺序是由操作系统决定的,并且受到多个因素的影响,如线程的优先级、线程的状态、调度算法等。

public class ThreadPriorityExample {
    public static void main(String[] args) {
        Thread thread1 = new SampleThread();
        Thread thread2 = new SampleThread();
        
        // 设置线程1的优先级为最低
        thread1.setPriority(Thread.MIN_PRIORITY);
        // 设置线程2的优先级为最高
        thread2.setPriority(Thread.MAX_PRIORITY);
        
        thread1.start();
        thread2.start();
    }
}

class SampleThread extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("当前执行的线程: " + Thread.currentThread().getName()
                    + ",优先级: " + Thread.currentThread().getPriority()
                    + ",运行次数: " + i);
        }
    }
}

在这个示例中,我们创建了两个线程thread1和thread2,它们都是SampleThread类的实例。然后,我们使用setPriority()方法将thread1的优先级设置为最低(1),将thread2的优先级设置为最高(10)。

在SampleThread中的run()方法中,线程会打印当前执行的线程名称、优先级以及运行次数。我们通过运行这段代码,可以观察到线程1的运行次数较少,而线程2的运行次数较多。这是因为线程2具有更高的优先级,相对而言更容易被调度执行。

三、守护线程:

守护线程(Daemon Thread)是在后台提供一种支持服务的线程,主要用于为其他非守护线程提供支持。

与普通线程不同,当所有非守护线程结束时,守护线程会被自动终止,无需显式地调用stop()或interrupt()方法来终止它们。

在Java中,可以通过setDaemon(true)方法将线程设置为守护线程。默认情况下,创建的线程都是非守护线程。将线程设置为守护线程必须在启动线程之前进行,否则会抛出IllegalThreadStateException异常。

public class DaemonThreadExample {
    public static void main(String[] args) {
        Thread thread = new SampleThread();
        
        // 设置线程为守护线程
        thread.setDaemon(true);
        
        thread.start();
        
        // 主线程休眠一秒钟
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("主线程结束");
    }
}

class SampleThread extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("守护线程正在运行");
            
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个示例中,我们创建了一个守护线程SampleThread。在main()方法中,我们将thread设置为守护线程,并启动它。主线程休眠一秒钟后输出"主线程结束",然后程序结束。

由于SampleThread是守护线程,它会在所有非守护线程(这里只有主线程)结束时自动终止。因此,当主线程结束后,守护线程也会随之结束。

需要注意的是,守护线程不能用于执行需要完整执行的任务,因为它们的终止时间无法确定。守护线程通常用于提供支持性质的服务,比如垃圾回收器(GC)线程。

四、礼让线程:

在多线程编程中,礼让线程是一种线程间的合作机制,它允许一个线程主动放弃当前的CPU执行权,让其他线程有机会执行。通过礼让线程,我们可以实现线程间的优先级调度或协调执行。

在Java中,可以使用Thread.yield()方法来实现线程的礼让。调用yield()方法的线程会暂停当前的执行,让出CPU资源给其他具有相同优先级的线程。然后,线程调度器会从等待队列中选择一个线程进行执行。

public class ThreadYieldExample {
    public static void main(String[] args) {
        Thread thread1 = new SampleThread("Thread 1");
        Thread thread2 = new SampleThread("Thread 2");

        thread1.start();
        thread2.start();
    }
}

class SampleThread extends Thread {
    public SampleThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(getName() + ": " + i);
            
            // 当 i 等于 3 的时候,调用 yield() 方法礼让CPU资源
            if (i == 3) {
                Thread.yield();
            }
        }
    }
}

在这个示例中,我们创建了两个线程thread1和thread2,它们都是SampleThread类的实例。在SampleThread的run()方法中,线程会打印名称和计数器变量的值。当计数器变量i等于3时,调用Thread.yield()方法礼让CPU资源。

通过运行这段代码,我们可以观察到以下结果:

Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
Thread 1: 3
Thread 2: 3
Thread 2: 4
Thread 2: 5
Thread 1: 4
Thread 1: 5

在这个示例中,当i等于3时,thread1主动礼让了CPU资源,此时thread2得到执行的机会。然后,thread2继续执行直到完成。最后,thread1再次获得CPU执行权并完成其剩余的计数。

需要注意的是,礼让线程的效果取决于操作系统和线程调度器的实现。在某些情况下,即使调用了yield()方法,当前线程仍然可能继续执行,而不是礼让给其他线程。因此,不能完全依赖yield()方法来实现线程调度。

五、插入线程:

当一个线程调用另一个线程的join()方法时,它会暂停自己的执行,并等待被调用线程执行完成后再继续执行。

join()方法有两个重载版本:

  • join():该方法会使当前线程等待被调用线程执行完成。
  • join(long millis):该方法会使当前线程等待被调用线程执行完成,但最多等待指定的时间(以毫秒为单位)。如果在指定时间内被调用线程没有执行完成,当前线程会继续执行。
public class JoinExample {
    public static void main(String[] args) {
        System.out.println("主线程开始执行");

        // 创建并启动线程A
        Thread threadA = new Thread(new TaskA());
        threadA.start();

        try {
            // 等待线程A执行完成
            threadA.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("主线程继续执行");
    }
}

class TaskA implements Runnable {
    @Override
    public void run() {
        System.out.println("线程A开始执行");

        try {
            // 模拟线程A的工作
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("线程A执行完成");
    }
}
主线程开始执行
线程A开始执行
线程A执行完成
主线程继续执行

从输出结果可以看出,在主线程中调用threadA.join()方法后,主线程进入等待状态,直到线程A执行完成,主线程才会继续执行。

join()方法常常用于需要等待其他线程完成工作后再进行后续操作的场景。例如,主线程需要等待所有子线程完成后再进行结果的汇总或后续计算等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值