java线程状态与锁:从新视角解析多线程编程(一)

一、java线程运行状态

在Arthas的线程面板中,你可以看到Java线程的各种状态。这些状态主要包括以下几种:

  1. NEW:这是线程刚刚被创建时的状态。在这个状态中,线程还没有开始执行。此状态的线程不会被执行,也不会占用CPU或内存资源。
  2. RUNNABLE:这个状态表示线程正在Java虚拟机中运行。这并不意味着线程一定在执行,而是说它正在占用CPU资源或者正在等待CPU资源。此状态的线程可能会占用CPU资源,因为它们是准备执行的。它们并不一定会占用大量的内存,除非它们正在执行的任务需要大量的内存。
  3. BLOCKED:当线程试图获取一个内部的对象锁(不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入BLOCKED状态。当持有锁的线程释放锁,BLOCKED状态的线程将有机会变成RUNNABLE状态。此状态的线程不会占用CPU资源,因为它们正在等待获取锁。它们也不会占用大量的内存,除非它们正在执行的任务需要大量的内存。
  4. WAITING:线程通过调用别的线程的 join()、wait()、LockSupport.park() 或 LockSupport.parkNanos() 方法,或者等待 java.util.concurrent - Lock或Condition时,进入这个状态。此状态的线程不会占用CPU资源,因为它们正在等待其他线程做出行动。它们也不会占用大量的内存,除非它们正在执行的任务需要大量的内存。
  5. TIMED_WAIT:这是线程在等待特定时间或者某个条件成立时的状态。当调用了如Thread.sleep(),Object.wait(long timeout),Thread.join(long millis),LockSupport.parkNanos(),或者等待 java.util.concurrent - Lock或Condition(带有超时时间)时,线程将进入这个状态。
  6. TIMED_WAITING:线程正在等待某个条件或者指定的时间,在这期间线程不会放弃CPU使用权。
  7. TERMINATED:表示线程已经执行完毕。

二、代码演示不同状态

接下来,我将通过代码示例说明在什么情况下会处于哪种状态。请注意,这些代码示例在Java环境下运行,并且你可以通过调试工具追踪线程的状态。

1. NEW状态:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // 线程执行的代码
    }
});

在上面的代码中,我们创建了一个新的线程对象,但是还没有调用start()方法启动它。此时,线程处于NEW状态。

2. RUNNABLE状态:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // 线程执行的代码
    }
});
thread.start();

在上面的代码中,我们创建了一个新的线程对象,并调用start()方法启动它。此时,线程处于RUNNABLE状态,表示它正在Java虚拟机中执行。

3. BLOCKED状态:

Object lock = new Object();
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (lock) {
            // 等待获取锁的代码
        }
    }
});
thread.start();

在上面的代码中,我们创建了一个新的线程对象,并在run()方法中使用synchronized关键字获取一个对象的锁。如果其他线程持有该锁,则当前线程会处于BLOCKED状态,等待获取锁。

此状态的线程不会获取CPU执行权,因为它们正在等待获取锁,而锁是由其他线程持有的。一旦锁被释放,BLOCKED状态的线程将有机会变成RUNNABLE状态,然后可以竞争CPU执行权。

4. WAITING状态:

Object lock = new Object();
Thread thread1 = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (lock) {
            // 等待其他线程做出行动的代码
            lock.wait();
        }
    }
});
Thread thread2 = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (lock) {
            // 通知等待的线程继续执行的代码
            lock.notify();
        }
    }
});
thread1.start();
thread2.start();

首先,创建一个Object对象lock作为监视器(monitor)。这个对象是用于同步的,它可以确保在任何时候只有一个线程可以访问被它保护的代码区域。

thread1是一个线程,在run()方法中,它首先获取了lock对象的锁(即进入synchronized块),然后调用lock.wait()方法。wait()方法使线程进入WAITING状态,并释放lock对象的锁,这样其他线程就可以获取这个锁了。在WAITING状态的线程不会消耗CPU资源,直到它被唤醒。

thread2也是一个线程,在run()方法中,它也首先获取了lock对象的锁,然后调用lock.notify()方法。notify()方法会唤醒等待在lock对象上的某一个线程(如果有的话)。注意,这里只是唤醒一个线程,如果有多个线程在等待,具体唤醒哪一个由JVM决定。被唤醒的线程将重新获得锁,并进入RUNNABLE状态,等待CPU时间片的分配。

这段代码的运行过程如下:

thread1启动,获取lock的锁,然后调用wait()方法,进入WAITING状态,释放锁。
thread2启动,获取lock的锁,然后调用notify()方法,唤醒等待在lock上的线程(即thread1)。
thread1被唤醒,重新获得锁,进入RUNNABLE状态。
由于已经没有其他线程在运行,所以thread1将继续执行,直到结束。

这种方式虽然简单,但很容易造成死锁等问题,实际中更常用的是java.util.concurrent包中的工具类来进行线程间的协作。

5. TIMED_WAIT状态:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            // 等待5秒钟的代码
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread.start();

在上面的代码中,我们创建了一个新的线程,该线程在启动后将进入TIMED_WAIT状态,等待5秒钟。如果在5秒内该线程被中断,它将抛出InterruptedException异常。在等待期间,线程不会执行任何代码,并且不会占用CPU资源。

6. TERMINATED状态:

一旦线程完成其生命周期,它就会进入TERMINATED状态。这意味着线程已经执行完毕,并且不会再执行任何代码。这个状态与前面五个状态有所不同,因为它表示线程已经结束,而不是正在执行。

总结:

Arthas中的线程面板提供了线程的各种状态,包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAIT和TERMINATED。这些状态描述了线程在生命周期中的不同阶段。通过理解这些状态,可以更好地了解线程的执行过程以及可能出现的问题。

三、TIMED_WAIT、TIMED_WAITING区别及代码示例

在Java编程中,TIMED_WAITTIMED_WAITING状态都是线程生命周期中的状态,用于描述线程在等待特定条件或时间的情况。

TIMED_WAIT状态表示线程在无限期地等待某个条件成立。当线程调用了Object.wait()方法时,它会进入TIMED_WAIT状态,并释放对象的锁。此时,线程会一直等待,直到其他线程调用了该对象的notify()notifyAll()方法,才会重新获取锁并进入可执行状态。

以下是一个示例代码,演示了TIMED_WAIT状态的情况:

public class TimedWaitExample {
    private static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread 1: Waiting...");
                    lock.wait(); // 进入 TIMED_WAIT 状态
                    System.out.println("Thread 1: Resumed");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2: Notifying...");
                lock.notify(); // 通知等待的线程继续执行
            }
        });

        thread1.start();
        Thread.sleep(1000); // 等待线程1进入等待状态
        thread2.start();
    }
}

在上面的代码中,线程1调用了lock.wait()方法,进入TIMED_WAIT状态,并等待其他线程的通知。线程2随后调用了lock.notify()方法,通知线程1继续执行。当线程1收到通知后,它会重新获取锁并进入可执行状态。

另一方面,TIMED_WAITING状态表示线程在有限时间内等待某个条件成立。当线程调用了Thread.sleep()Object.wait(long timeout)方法时,它会进入TIMED_WAITING状态,并在指定的时间内等待。如果在超时时间内条件未满足,线程将重新进入可执行状态。

以下是一个示例代码,演示了TIMED_WAITING状态的情况:

public class TimedWaitingExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("Thread: Waiting for 5 seconds...");
                Thread.sleep(5000); // 进入 TIMED_WAITING 状态,等待 5 秒钟
                System.out.println("Thread: Resumed");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
    }
}

在上面的代码中,线程调用了Thread.sleep(5000)方法,进入TIMED_WAITING状态,并在5秒钟内等待。当5秒钟过去后,线程将重新进入可执行状态,并继续执行后续的代码。

四、WAITING、BLOCKED区别及代码示例

在Java多线程编程中,WAITINGBLOCKED是两种线程状态,它们的区别如下:

  • WAITING:线程处于等待状态,它正在等待另一个线程执行某个特定的操作,比如调用Object.wait()Thread.join()LockSupport.park()方法。在WAITING状态的线程不会消耗CPU资源。
  • BLOCKED:线程处于阻塞状态,它正在等待获取一个锁,但锁被其他线程持有。在BLOCKED状态的线程不会消耗CPU资源。

下面是一些代码示例来说明这两种状态的区别:

  1. WAITING状态示例:
public class WaitingExample {
    private static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread 1 is waiting...");
                    lock.wait(); // 等待其他线程通知
                    System.out.println("Thread 1 is resuming...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2 is notifying...");
                lock.notify(); // 通知等待的线程
            }
        });

        thread1.start();
        Thread.sleep(1000); // 让thread1先运行一会儿
        thread2.start();
    }
}

在上面的代码中,thread1进入WAITING状态,因为它调用了lock.wait()方法。之后,thread2调用lock.notify()方法通知thread1,使其从WAITING状态变为RUNNABLE状态。

  1. BLOCKED状态示例:
public class BlockedExample {
    private static Object lock = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 1 is running...");
                try {
                    Thread.sleep(5000); // 模拟耗时操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2 is blocked...");
                // thread2将一直等待,直到thread1释放锁
            }
        });

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

在上面的代码中,thread1持有锁并执行了一个耗时操作,而thread2试图获取同一个锁但失败,因此它进入BLOCKED状态,直到thread1释放锁。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java编程:架构设计与企业真实项目案例

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值