做网站花都,网站服务器ip地址查询,网站推广的途径和要点,河间网站网站建设目录 1 线程之间的通信方式主要有以下几种2 共享变量3 锁机制4 条件变量5 信号量6 管道 1 线程之间的通信方式主要有以下几种 在实际开发时#xff0c;一个进程中往往有很多个线程#xff0c;大多数线程之间往往不是绝对独立的#xff0c;比如说我们需要将A和B 两个线程的执… 目录 1 线程之间的通信方式主要有以下几种2 共享变量3 锁机制4 条件变量5 信号量6 管道 1 线程之间的通信方式主要有以下几种 在实际开发时一个进程中往往有很多个线程大多数线程之间往往不是绝对独立的比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上又或者比较典型的消费者-生产者模式在这些场景下线程间通信成了我们必须使用的手段那么线程之间怎么通信呢
线程间通信方式从实现本质来讲主要可以分为两大类共享内存和消息传递。
相信大家还记得在内存模型一节我们提到多线程并发情况下的三大特性原子性有序性可见性其所对应的解决方案就可以用来实现线程间通信这些解决方案的本质就是共享内存。
对于消息传递而言最经典的实现就是我们的Handler机制在子线程使用主线程的Handler对象将一些信息发送到主线程以便进行处理。
下面我们来看一些线程间通信的典型实现
2 共享变量
共享变量线程之间可以通过共享变量来进行通信。不同的线程可以共享同一个变量并在变量上进行读写操作。需要注意的是共享变量可能会引发线程安全问题需要通过同步机制来确保线程安全。
public class SharedData {private int value;public synchronized int getValue() { return value; }public synchronized void setValue(int value) { this.value value; }
} 在这个示例中定义了一个共享数据类 SharedData其中包含一个整型变量 value 和两个同步方法 getValue() 和 setValue()用于获取和设置变量的值。由于这两个方法都是同步的因此多个线程可以安全地访问该变量。
public class SharedDataExample {public static void main(String[] args) throws InterruptedException {SharedData sharedData new SharedData();Thread thread1 new Thread(() - {for (int i 0; i 10; i) {sharedData.setValue(i);System.out.println(Thread.currentThread().getName() write sharedData.getValue());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}});Thread thread2 new Thread(() - {for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName() read sharedData.getValue());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}});thread1.start();thread2.start();thread1.join();thread2.join();}
} 在这个示例中创建了两个线程分别用于读写共享数据 SharedData多次执行该示例可以看到控制台输出表明两个线程在安全地访问共享变量。
结果如图
3 锁机制
锁机制锁机制是一种常用的线程同步机制可以保证在同一时间只有一个线程能够访问共享资源。Java提供了多种锁类型如 synchronized 关键字、ReentrantLock 类等。
public class LockExample {private static Lock lock new ReentrantLock();private static int count 0;private static void increase() {lock.lock();try {count;} finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {Thread thread1 new Thread(() - {for (int i 0; i 10000; i) {increase();}});Thread thread2 new Thread(() - {for (int i 0; i 10000; i) {increase();}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(count);}
} 在这个示例中使用了 Lock 接口和 ReentrantLock 类来对计数器进行同步多次执行该示例可以看到最终输出的计数器值为 20000。
结果如图
4 条件变量
条件变量条件变量是一种线程间通信机制它用于在一个共享资源上等待某个条件的成立。Java 提供了 Condition 接口来支持条件变量的实现在使用 Condition 时需要先获取锁然后调用 await() 方法等待条件成立当条件成立时可以通过 signal() 或 signalAll() 方法唤醒等待该条件的线程。
public class ConditionExample {private static Lock lock new ReentrantLock();private static Condition condition lock.newCondition();private static int count 0;private static void await() throws InterruptedException {lock.lock();try {condition.await();} finally {lock.unlock();}}private static void signal() {lock.lock();try {condition.signalAll();} finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {Thread thread1 new Thread(() - {for (int i 0; i 10; i) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}count;System.out.println(Thread.currentThread().getName() increase count to count);if (count 5) {signal();}}});Thread thread2 new Thread(() - {try {await();System.out.println(Thread.currentThread().getName() receive signal, count is count);} catch (InterruptedException e) {e.printStackTrace();}});thread1.start();thread2.start();thread1.join();thread2.join();}
} 在这个示例中使用了 Lock 接口和 Condition 接口来定义了一个计数器线程1每次增加计数器的值并判断是否达到条件当计数器达到条件时调用 signal() 方法通知线程2线程2等待条件成立后执行相应的操作。 5 信号量
信号量信号量是一种常见的线程同步机制可用于控制多个线程对共享资源的访问。Java 提供了 Semaphore 类来实现信号量Semaphore 类有两个常用的方法 acquire() 和 release()分别用于获取和释放信号量。
public class SemaphoreExample {private static Semaphore semaphore new Semaphore(2);private static void doWork() throws InterruptedException {semaphore.acquire();System.out.println(Thread.currentThread().getName() start working);Thread.sleep(1000);System.out.println(Thread.currentThread().getName() finish working);semaphore.release();}public static void main(String[] args) throws InterruptedException {Thread thread1 new Thread(() - {try {doWork();} catch (InterruptedException e) {e.printStackTrace();}});Thread thread2 new Thread(() - {try {doWork();} catch (InterruptedException e) {e.printStackTrace();}});Thread thread3 new Thread(() - {try {doWork();} catch (InterruptedException e) {e.printStackTrace();}});thread1.start();thread2.start();thread3.start();thread1.join();thread2.join();thread3.join();}
} 在这个示例中使用了 Semaphore 类来定义了一个信号量线程1、线程2、线程3都需要获取信号量才能进行工作每次执行 doWork() 方法需要占用资源执行完毕后释放信号量。 6 管道
管道管道是一种用于线程间通信的高级机制它可以实现一个线程向另一个线程传送数据。Java 提供了 PipedInputStream 和 PipedOutputStream 两个类来支持管道的实现其中 PipedInputStream 用于读取数据PipedOutputStream 用于写入数据。
public class PipeExample {static class WriterThread extends Thread {private PipedOutputStream output;WriterThread(PipedOutputStream output) {this.output output;}Overridepublic void run() {try {for(int i1;i10;i) {output.write(i);System.out.println(写入数据 i);Thread.sleep(1000);}} catch(Exception e) {e.printStackTrace();} finally {try {output.close();} catch(Exception e) {e.printStackTrace();}}}}static class ReaderThread extends Thread {private PipedInputStream input;ReaderThread(PipedInputStream input) {this.input input;}Overridepublic void run() {try {int value;while((valueinput.read()) ! -1) {System.out.println(读取数据 value);}} catch(Exception e) {e.printStackTrace();} finally {try {input.close();} catch(Exception e) {e.printStackTrace();}}}}public static void main(String[] args) throws IOException {PipedOutputStream output new PipedOutputStream();PipedInputStream input new PipedInputStream(output);Thread thread1 new WriterThread(output);Thread thread2 new ReaderThread(input);thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}}
}在这个示例中使用了 PipedOutputStream 类和 PipedInputStream 类来定义了一个管道线程1向管道中写入数据线程2从管道中读取数据通过管道来实现两个线程之间的通信。
运行结果
需要注意的是以上通信方式都需要在多线程程序中谨慎使用需要考虑线程安全和性能等方面的问题。为了确保程序正确、高效地运行需要根据具体情况选择合适的线程通信方式并进行相应的测试和优化。