多线程的状态
在Java中,一个线程的生命周期有以下几种状态:
-
新建(New):当线程对象被创建时,线程处于新建状态。此时线程对象存在,但还没有调用start()方法启动线程。
-
运行(Runnable):当线程调用start()方法后,线程进入就绪状态,等待被分配CPU时间片执行。当线程获取到CPU时间片后,线程进入运行状态执行任务。
-
阻塞(Blocked):线程在执行过程中,可能会因为某些原因(如等待I/O操作、等待获取锁等)而暂时停止执行。此时线程进入阻塞状态,等待特定条件满足后重新进入就绪状态。
-
等待(Waiting):线程在执行过程中,可能会因为调用了wait()方法而进入等待状态。此时线程释放持有的锁,并等待其他线程调用notify()、notifyAll()方法唤醒自己。
-
超时等待(Timed Waiting):线程在执行过程中,可能会因为调用了sleep()方法或者带有超时参数的wait()方法而进入超时等待状态。超过指定时间后,线程会被自动唤醒并进入就绪状态。
-
终止(Terminated):线程执行完任务或者发生异常导致线程终止时,线程进入终止状态。
线程的状态之间的流转如下:
-
新建 -> 运行:调用start()方法启动线程,线程进入就绪状态等待CPU调度。
-
运行 -> 阻塞:线程在执行过程中,由于某些原因(如等待I/O操作、等待获取锁等)暂停执行。
-
阻塞 -> 运行:阻塞状态解除后,线程重新进入就绪状态等待CPU调度。
-
运行 -> 等待:线程调用了wait()方法,线程进入等待状态。
-
等待 -> 运行:其他线程调用了notify()、notifyAll()方法,或者等待时间到达,线程被唤醒并进入就绪状态。
-
运行 -> 超时等待:线程调用了sleep()方法或者带有超时参数的wait()方法,线程进入超时等待状态。
-
超时等待 -> 运行:超时等待时间到达,线程被自动唤醒并进入就绪状态。
-
运行 -> 终止:线程执行完任务或者发生异常导致线程终止。
启动线程方法 start()和 run()区别
start()和run()是Java中用于启动线程的两种方法。
start()方法用于启动一个新的线程,并在新的线程中执行run()方法。当start()方法被调用时,会创建一个新的线程,并且该线程会执行run()方法中的代码。
run()方法定义了线程的主体,包含了线程要执行的代码。当run()方法被调用时,会在当前线程中执行run()方法中的代码,而不会创建新的线程。
所以,区别在于start()方法会创建一个新的线程,而run()方法只是在当前线程中执行run()方法中的代码。一般情况下,应该使用start()方法来启动线程,这样可以实现多线程并发执行。使用run()方法启动线程,相当于在当前线程中顺序执行run()方法中的代码,不会实现多线程的效果。
线程中的 wait()和 sleep()方法区别
wait()方法和sleep()方法都是线程中的方法,但是它们的功能和使用方式有所不同。
- wait()方法:
- wait()方法是Object类中的方法,需要在同步代码块或同步方法中使用。当一个线程调用对象的wait()方法时,该线程会释放对象的锁,并进入等待状态,直到其他线程调用同一个对象的notify()或notifyAll()方法来唤醒等待中的线程。
- wait()方法的调用可以帮助线程间的协调合作,允许线程之间等待某个条件满足后再继续执行。
- wait()方法必须在synchronized块中调用,否则会在运行时抛出IllegalMonitorStateException异常。
- sleep()方法:
- sleep()方法是Thread类的静态方法,用于暂停当前线程的执行一段时间,不释放当前线程所持有的锁。
- sleep()方法的调用不需要在同步代码块或同步方法中,任何地方都可以调用。
- sleep()方法可以用来模拟线程间的时间间隔,或者在某些需要睡眠一段时间的情况下使用。
多线程同步方法
- synchronized关键字:通过在方法或代码块前加上synchronized关键字,可以实现对方法或代码块的同步。一次只能有一个线程访问该同步方法或代码块,其他线程需要等待。 代码示例:
class Counter {
private int count;
public synchronized void increment() {
count++;
}
}
- Lock接口:Java提供了Lock接口及其实现类ReentrantLock来实现更灵活的同步操作。通过调用lock()方法获得锁,调用unlock()方法释放锁。 代码示例:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private int count;
private Lock lock;
public Counter() {
count = 0;
lock = new ReentrantLock();
}
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
- synchronized关键字与wait()、notify()、notifyAll()方法:可以使用synchronized关键字结合wait()、notify()、notifyAll()方法实现线程间的等待和唤醒操作。 代码示例:
class MyThread implements Runnable {
private Object lock;
public MyThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
try {
// 线程等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 线程被唤醒后执行的操作
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread thread = new Thread(new MyThread(lock));
thread.start();
// 唤醒线程
synchronized (lock) {
lock.notify();
}
}
}
总结
多线程的状态可以总结为以下几种:
-
新建(New):线程被创建但还没有启动。
-
就绪(Runnable):线程被调度,并且准备开始执行,但还没有开始执行。
-
运行(Running):线程正在执行中。
-
阻塞(Blocked):线程因为某种原因被阻塞,例如等待 IO 操作完成或在等待锁释放。
-
等待(Waiting):线程被指定等待某个条件满足,例如调用了对象的 wait() 方法。
-
超时等待(Timed Waiting):线程被指定等待一段时间,例如调用了 Thread.sleep() 方法或带有超时参数的 wait() 方法。
-
终止(Terminated):线程执行完毕或者异常终止。