在Java并发编程中,线程同步是一个至关重要的概念,它确保了多个线程在访问共享资源时不会相互干扰,从而避免了数据不一致和竞态条件等问题。wait()和sleep()是Java中用于线程同步的两个关键字,虽然它们都涉及到线程的暂停,但它们的用法和目的却大不相同。本文将深入探讨这两个关键字的使用方法,帮助读者更好地理解和避免并发编程中的陷阱。
wait()方法
wait()方法是Object类的一部分,它使得当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法。以下是wait()方法的一些关键点:
- 调用时机:
wait()方法必须在同步代码块或同步方法内部调用,否则会抛出IllegalMonitorStateException异常。 - 释放锁:当
wait()方法被调用时,当前线程会释放它所持有的锁,并进入等待状态。 - 等待条件:线程会等待直到另一个线程调用
notify()或notifyAll()方法,或者等待超时或线程被中断。
以下是一个使用wait()方法的简单示例:
public class WaitExample {
public static void main(String[] args) {
Object lock = new Object();
Thread producer = new Thread(new Producer(lock));
Thread consumer = new Thread(new Consumer(lock));
producer.start();
consumer.start();
}
}
class Producer implements Runnable {
private Object lock;
public Producer(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
try {
System.out.println("Producer is producing...");
lock.wait();
System.out.println("Producer is notified and continues.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Object lock;
public Consumer(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
try {
System.out.println("Consumer is consuming...");
lock.wait();
System.out.println("Consumer is notified and continues.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
sleep()方法
sleep()方法是Thread类的一部分,它使得当前线程暂停执行指定的毫秒数。以下是sleep()方法的一些关键点:
- 暂停时间:
sleep()方法接受一个参数,表示线程将暂停的毫秒数。 - 不会释放锁:与
wait()不同,sleep()方法不会释放当前线程持有的锁。 - 不响应中断:
sleep()方法不会响应中断,即使当前线程被中断,它也会继续睡眠直到指定的毫秒数结束。
以下是一个使用sleep()方法的简单示例:
public class SleepExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
System.out.println("Thread is sleeping for 2 seconds...");
Thread.sleep(2000);
System.out.println("Thread has woken up.");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}
总结
wait()和sleep()方法在Java并发编程中扮演着不同的角色。wait()用于线程间的通信,而sleep()用于线程的暂停。正确使用这两个方法可以避免并发编程中的许多陷阱,例如死锁、数据不一致和竞态条件。通过理解它们的用法和区别,开发者可以编写出更加健壮和高效的并发程序。
