招行一面:Java 的线程如何通信?

在 Java 中,线程是执行的最小单元,那么线程之间是如何通信的呢?这篇文章我们一起来分析五种常用的方式。
首页 新闻资讯 行业资讯 招行一面:Java 的线程如何通信?

在 Java中,线程是执行的最小单元,那么线程之间是如何通信的呢?这篇文章我们一起来分析五种常用的方式。

  • 使用 wait()、notify() 和 notifyAll()

  • 使用 BlockingQueue

  • Exchanger

  • 使用 Locks 和 Condition

  • 使用 Semaphore

1157f9f418b018474c0474ad12e4f6404d1855.jpg

1. 使用 wait()、notify() 和 notifyAll()

Java的 Object 类提供了 wait()、notify() 和 notifyAll() 方法,这些方法可以用来实现线程之间的通信,这些方法必须在同步块或同步方法中调用。

  • **wait()**:使当前线程进入等待状态,直到其他线程调用 notify() 或 notifyAll()。

  • **notify()**:唤醒在该对象监视器上等待的单个线程。

  • **notifyAll()**:唤醒在该对象监视器上等待的所有线程。

示例代码:

classSharedResource{privateint data;privateboolean hasData=false;publicsynchronizedvoidproduce(int value)throws InterruptedException{while(hasData){wait();}this.data=value;hasData=true;notify();}publicsynchronized intconsume()throws InterruptedException{while(!hasData){wait();}hasData=false;notify();returndata;}}publicclassProducerConsumerExample{publicstaticvoidmain(String[]args){SharedResource resource=newSharedResource();Thread producer=newThread(()->{try{for(int i=0;i<10;i++){resource.produce(i);System.out.println("Produced: "+i);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});Thread consumer=newThread(()->{try{for(int i=0;i<10;i++){int data=resource.consume();System.out.println("Consumed: "+data);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});producer.start();consumer.start();}}

2. 使用 BlockingQueue

BlockingQueue 是Java中一个强大的接口,提供了线程安全的队列操作,并且可以在生产者-消费者模式中使用。BlockingQueue 不需要显式地使用同步机制,它内部已经处理好了线程同步问题。

示例代码:

importjava.util.concurrent.ArrayBlockingQueue;importjava.util.concurrent.BlockingQueue;publicclassBlockingQueueExample{publicstaticvoidmain(String[]args){BlockingQueue<Integer>queue=newArrayBlockingQueue<>(10);Thread producer=newThread(()->{try{for(int i=0;i<10;i++){queue.put(i);System.out.println("Produced: "+i);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});Thread consumer=newThread(()->{try{for(int i=0;i<10;i++){int data=queue.take();System.out.println("Consumed: "+data);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});producer.start();consumer.start();}}

3. 使用 Locks 和 Condition

Java提供了 java.util.concurrent.locks 包,其中包含了 Lock 接口和 Condition 接口。Condition 提供了类似于 wait()、notify() 和 notifyAll() 的方法,但它们与 Lock 对象一起使用,提供了更灵活的线程通信机制。

示例代码:

importjava.util.concurrent.locks.Condition;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;classSharedResourceWithLock{privateint data;privateboolean hasData=false;privateLock lock=newReentrantLock();privateCondition condition=lock.newCondition();publicvoidproduce(int value)throws InterruptedException{lock.lock();try{while(hasData){condition.await();}this.data=value;hasData=true;condition.signal();}finally{lock.unlock();}}publicintconsume()throws InterruptedException{lock.lock();try{while(!hasData){condition.await();}hasData=false;condition.signal();returndata;}finally{lock.unlock();}}}publicclassLockConditionExample{publicstaticvoidmain(String[]args){SharedResourceWithLock resource=newSharedResourceWithLock();Thread producer=newThread(()->{try{for(int i=0;i<10;i++){resource.produce(i);System.out.println("Produced: "+i);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});Thread consumer=newThread(()->{try{for(int i=0;i<10;i++){int data=resource.consume();System.out.println("Consumed: "+data);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});producer.start();consumer.start();}}

4. 使用 Exchanger

Exchanger 是一个用于线程间交换数据的同步点。两个线程可以在此同步点交换数据,Exchanger 的 exchange() 方法用于在两个线程之间交换数据。

示例代码:

importjava.util.concurrent.Exchanger;publicclassExchangerExample{publicstaticvoidmain(String[]args){Exchanger<Integer>exchanger=newExchanger<>();Thread producer=newThread(()->{try{for(int i=0;i<10;i++){System.out.println("Produced: "+i);exchanger.exchange(i);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});Thread consumer=newThread(()->{try{for(int i=0;i<10;i++){int data=exchanger.exchange(null);System.out.println("Consumed: "+data);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});producer.start();consumer.start();}}

5. 使用 Semaphore

Semaphore 是一个计数信号量,通常用于限制对某些资源的访问。它可以用于控制线程访问共享资源的数量,这在某些情况下也可以用作线程间通信的机制。

示例代码:

importjava.util.concurrent.Semaphore;classSemaphoreSharedResource{privateint data;privateSemaphore semaphore=newSemaphore(1);publicvoidproduce(int value)throws InterruptedException{semaphore.acquire();try{this.data=value;System.out.println("Produced: "+value);}finally{semaphore.release();}}publicintconsume()throws InterruptedException{semaphore.acquire();try{System.out.println("Consumed: "+data);returndata;}finally{semaphore.release();}}}publicclassSemaphoreExample{publicstaticvoidmain(String[]args){SemaphoreSharedResource resource=newSemaphoreSharedResource();Thread producer=newThread(()->{try{for(int i=0;i<10;i++){resource.produce(i);}}catch(InterruptedException e){Thread.currentThread().interrupt();}});Thread consumer=newThread(()->{try{for(int i=0;i<10;i++){resource.consume();}}catch(InterruptedException e){Thread.currentThread().interrupt();}});producer.start();consumer.start();}}

结论

本文,我们分析了 Java线程通信的5种常见方式:

  • wait()/notify() 是一种低级别的同步机制,适合需要精细控制的场合;

  • BlockingQueue 和 Exchanger 提供了更高层次的抽象,简化了线程间的数据交换;

  • Locks 和 Condition 提供了更灵活的锁机制,适合复杂的同步场景;

  • Semaphore 则用于控制资源访问。

在实际应用中,需要选择哪种方式取决于具体的应用场景和需求。如何你有好的通信方式,欢迎评论区留言。

36    2024-11-11 16:40:04    Java 线程 通信