Runnable 和 Thread 用哪个好
使用Runnable接口的好处是:
- 避免了单继承的限制:当你的类已经继承了另一个类时,你仍然可以实现Runnable接口来创建线程。
- 提高代码的复用性:你可以将Runnable对象传递给多个线程来执行,从而实现代码的复用。
- 适合资源共享:多个线程可以共享同一个Runnable对象,从而实现对同一个资源的访问。
使用Thread类的好处是:
- 简单直观:Thread类提供了一些常用的方法,如start()、sleep()等,可以更方便地控制线程的执行。
- 可以直接继承Thread类来创建线程,不需要实现接口。
如果你的类已经继承了另一个类,或者需要与多个线程共享资源,那么使用Runnable接口是一个更好的选择。如果你只需要简单地创建一个线程并执行任务,可以直接继承Thread类。
notify 和 notifyAll 有什么区别
在 Java 中,notify() 和 notifyAll() 都是 Object 类中的方法,用于唤醒等待在当前对象上的线程。区别在于:
- notify() 方法会唤醒在对象的等待池中等待时间最长的一个线程,该线程将进入可运行状态,但并不能立即获得锁资源。如果有多个线程等待,则只有一个线程能被唤醒。
- notifyAll() 方法会唤醒所有在对象的等待池中等待的线程,所有线程都将进入可运行状态,但并不能立即获得锁资源。
下面是一个例子,通过 synchronized、wait()、notify() 方法演示了 notify() 和 notifyAll() 的区别:
public class NotifyExample {public static void main(String[] args) {Message message = new Message();Thread thread1 = new Thread(new Waiter(message), "Waiter1");Thread thread2 = new Thread(new Waiter(message), "Waiter2");Thread thread3 = new Thread(new Notifier(message), "Notifier");thread1.start();thread2.start();thread3.start();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}message.setReady(true);synchronized (message) {message.notify(); // 唤醒等待时间最长的一个线程}}
}class Message {private boolean ready;public boolean isReady() {return ready;}public void setReady(boolean ready) {this.ready = ready;}
}class Waiter implements Runnable {private final Message message;public Waiter(Message message) {this.message = message;}@Overridepublic void run() {synchronized (message) {try {if (!message.isReady()) {System.out.println(Thread.currentThread().getName() + ": 正在等待消息...");message.wait();}} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ": 收到消息!");}}
}class Notifier implements Runnable {private final Message message;public Notifier(Message message) {this.message = message;}@Overridepublic void run() {synchronized (message) {System.out.println(Thread.currentThread().getName() + ": 准备通知等待的线程");message.setReady(true);
// message.notify(); // 使用 notify() 方法message.notifyAll(); // 使用 notifyAll() 方法}}
}
运行上述代码,结果会根据调用的 notify() 或 notifyAll() 方法而有所不同。如果使用 notify() 方法,则只有一个 Waiter 线程会被唤醒并继续执行;如果使用 notifyAll() 方法,则所有的 Waiter 线程都会被唤醒并继续执行。
总结
在Java中,notify()和notifyAll()是用于线程间通信的方法。
-
notify()方法:该方法用于唤醒在对象的等待池中等待的单个线程。如果有多个线程在等待,则随机选择一个线程被唤醒。被唤醒的线程将进入就绪状态,等待获取对象的锁。
-
notifyAll()方法:该方法用于唤醒在对象的等待池中等待的所有线程。被唤醒的线程将进入就绪状态,等待获取对象的锁。notifyAll()相当于广播通知,通知所有等待的线程。
-
Runnable接口:Runnable是一个函数式接口,用于定义一个可以被线程执行的任务。实现Runnable接口的类可以被传递给Thread类的构造方法,从而创建一个线程。Runnable接口只有一个run()方法,需要在该方法中定义线程的执行逻辑。
-
Thread类:Thread类是Java中表示线程的类,可以通过继承Thread类或传递实现Runnable接口的对象来创建线程。Thread类提供了一些方法用于管理线程,如start()用于启动线程,sleep()用于使线程休眠,join()用于等待其他线程执行完毕等。
- notify()和notifyAll()方法用于线程间通信,唤醒等待的线程。
- Runnable接口用于定义一个可以被线程执行的任务。
- Thread类是Java中表示线程的类,可以通过继承Thread类或传递实现Runnable接口的对象来创建线程。