在Java中,notify和notifyAll是用于线程间通信的方法,用于唤醒等待中的线程。
用于唤醒在对象上等待的单个线程。如果有多个线程在等待同一个对象的监视器锁,则只会唤醒其中一个线程,具体唤醒哪个线程是不确定的。
用于唤醒在对象上等待的所有线程。如果有多个线程在等待同一个对象的监视器锁,则会唤醒所有等待的线程,并使它们竞争锁资源。
下面是一个使用notify和notifyAll的示例:
class Message {
private boolean isProduced = false;
public synchronized void produce() {
if (isProduced) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Producing message");
isProduced = true;
notify(); // 唤醒等待中的单个线程
}
public synchronized void consume() {
if (!isProduced) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Consuming message");
isProduced = false;
notifyAll(); // 唤醒等待中的所有线程
}
}
class Producer implements Runnable {
private Message message;
public Producer(Message message) {
this.message = message;
}
@Override
public void run() {
while (true) {
message.produce();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Message message;
public Consumer(Message message) {
this.message = message;
}
@Override
public void run() {
while (true) {
message.consume();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Message message = new Message();
Thread producerThread = new Thread(new Producer(message));
Thread consumerThread = new Thread(new Consumer(message));
producerThread.start();
consumerThread.start();
}
}
在上面的示例中,Message类表示一个消息对象,isProduced表示是否已经生产了消息。
Producer类和Consumer类分别表示生产者和消费者线程。
在生产者线程中,调用message.produce()方法生产消息,并通过notify()方法唤醒等待中的消费者线程。
在消费者线程中,调用message.consume()方法消费消息,并通过notifyAll()方法唤醒等待中的生产者和消费者线程。
通过运行上述示例,可以观察到生产者和消费者线程之间的交替执行。当生产者线程生产消息时,消费者线程会被唤醒并消费消息,然后生产者线程会被唤醒并继续生产消息,如此循环。这个例子演示了notify和notifyAll的不同行为。
Java中的wait()和sleep()方法都可以用于线程的控制,但是两者的作用和使用方式有所不同。
wait()方法是Object类中定义的一个方法,它的作用是使当前线程进入等待状态,直到其他线程调用notify()或notifyAll()方法唤醒它。
wait()方法必须在synchronized块中调用,否则会抛出IllegalMonitorStateException异常。
wait()方法的使用流程如下:
✨示例:✨
public class WaitDemo {
public static void main(String[] args) {
final Object lock = new Object();
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread 1 is waiting");
lock.wait(); // 线程1进入等待状态
System.out.println("Thread 1 is awake");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 is notifying");
lock.notify(); // 唤醒等待的线程1
}
});
thread1.start();
thread2.start();
}
}
在上述示例中,线程1在synchronized块中调用了lock对象的wait()方法,进入等待状态。而线程2在synchronized块中调用了lock对象的notify()方法,唤醒了线程1。
输出结果如下:
Thread 1 is waiting
Thread 2 is notifying
Thread 1 is awake
sleep()方法是Thread类中定义的一个方法,它的作用是使当前线程暂停执行指定的时间。
sleep()方法不会释放锁,因此可以在任何地方调用。
sleep()方法的使用方式为:
Thread.sleep(时间);
其中,时间参数为毫秒值。
示例:
public class SleepDemo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
System.out.println("Thread is sleeping");
Thread.sleep(2000); // 线程暂停2秒
System.out.println("Thread is awake");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}
在上述示例中,线程暂停了2秒后输出"Thread is awake"。
输出结果如下:
Thread is sleeping
Thread is awake
sleep和wait对比:
在Java中,run()方法和start()方法均与线程相关。
run()方法是Thread类中定义的一个普通方法,用于定义线程的执行逻辑。
在使用Thread类创建线程时,可以重写run()方法,将自定义的代码逻辑写在run()方法中。
当线程被调度执行时,会自动调用run()方法中的代码逻辑。
一般情况下,我们不直接调用run()方法,而是通过调用start()方法来启动线程。
下面是一个简单的示例代码:
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Thread " + Thread.currentThread().getId() + ": " + i);
}
}
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 启动线程1
thread1.start();
// 直接调用run()方法,不会创建新的线程
thread2.run();
}
}
运行以上代码,会输出类似以下的结果:
Thread 9: 0
Thread 9: 1
Thread 9: 2
Thread 9: 3
Thread 9: 4
Thread 10: 0
Thread 10: 1
Thread 10: 2
Thread 10: 3
Thread 10: 4
start()/run()方法对比: