本文小编为大家详细介绍“Java中不同的线程间数据怎么通信”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中不同的线程间数据怎么通信”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
1、多线程如何共享数据
多线程数据共享可以分为以下2种情况,线程实现代码相同及线程实现代码不同。
线程实现代码相同
即runnable中的代码一致,这样可以直接在实现中定义成员变量直接共享
public class SharedSameRunnableDemo { public static void main(String[] args) { Runnable runnable = new MySameRunnable(); Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); } private static class MySameRunnable implements Runnable { private int sharedData = 0; @Override public synchronized void run() { for (int i = 0; i < 5; i++) { sharedData++; System.out.println("Thread: " + Thread.currentThread().getName() + ", sharedData: " + sharedData); } } } }
在上面的示例中,我们定义了一个名为 MySameRunnable 的内部类它的共享变量是sharedData,它实现了Runnable 接口,并重写了 run() 方法。在 run() 方法中,我们使用了 synchronized 关键字来保证线程安全。然后在main() 方法中,我们创建了一个 MySameRunnable 实例 runnable,并将其传入两个不同的线程对象中。最后启动这两个线程。由于这两个线程共享同一个 MySameRunnable 实例,因此它们执行的代码是相同的,并且可以访问和修改sharedData 变量。通过这种方式,就可以实现多个线程共享数据,并确保线程安全。
线程实现代码不相同
即runnable中的代码不一致,MyRunnable1 MyRunnable2,利用一个对象SharedData,把runnable中的方法封装到这个对象中去,数据也在这个对象中。如果多个线程实现的代码不同,并且需要共享变量,可以使用一个单独的类来存储这些共享变量,并将它传递给所有的 Runnable 实例。以下是一个简单的示例代码:
public class SharedDifferentRauuableDemo { public static void main(String[] args) { SharedData sharedData = new SharedData(); Thread thread1 = new Thread(new MyRunnable1(sharedData)); Thread thread2 = new Thread(new MyRunnable2(sharedData)); thread1.start(); thread2.start(); } private static class SharedData { private int data = 0; public synchronized void increment() { data++; System.out.println("IncrementThread: " + data); } public synchronized void decrement() { data--; System.out.println("DecrementThread: " + data); } } private static class MyRunnable1 implements Runnable { private SharedData sharedData; public MyRunnable1(SharedData sharedData) { this.sharedData = sharedData; } @Override public void run() { for (int i = 0; i < 5; i++) { sharedData.increment(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } private static class MyRunnable2 implements Runnable { private SharedData sharedData; public MyRunnable2(SharedData sharedData) { this.sharedData = sharedData; } @Override public void run() { for (int i = 0; i < 5; i++) { sharedData.decrement(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
在上面的示例中,我们定义了一个 SharedData 类来存储共享变量 data。这个类包含两个同步方法 increment() 和 decrement(),用于增加和减少 data 的值,并输出当前的值。然后我们创建了两个 MyRunnable1 和 MyRunnable2 实例,它们分别传递了相同的 SharedData 对象。在 run() 方法中,它们调用 SharedData 对象的 increment() 和 decrement() 方法来进行数据修改,并使用 Thread.sleep() 方法让线程休眠一段时间。
通过这种方式,就可以实现多个线程共享数据,并确保线程安全。
2、子线程如何继承父线程数据
通过 InteritableThreadLocal实现共享
public class InheritableThreadLocalDemo { private static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>(); public static void main(String[] args) { inheritableThreadLocal.set("Hello, World!"); Thread parentThread = new Thread(() -> { System.out.println("Parent Thread: " + inheritableThreadLocal.get()); inheritableThreadLocal.set("Hello from Parent Thread!"); Thread childThread = new Thread(() -> { System.out.println("Child Thread: " + inheritableThreadLocal.get()); }); childThread.start(); try { childThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Parent Thread: " + inheritableThreadLocal.get()); }); parentThread.start(); try { parentThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main Thread: " + inheritableThreadLocal.get()); inheritableThreadLocal.remove(); } }
在上面的示例中,我们创建了一个 InheritableThreadLocal 对象,并将其设置为“Hello, World!”。然后,我们创建了一个名为“parentThread”的线程,并在其中输出 inheritableThreadLocal 的值。接下来,我们在父线程中将 inheritableThreadLocal 的值设置为“Hello from Parent Thread!”,并创建了一个名为“childThread”的线程,在其中输出 inheritableThreadLocal 的值。
注意:由于 InheritableThreadLocal 是可继承的,所以在子线程中也能够获取到父线程中设置的值。因此,当我们在子线程中输出 inheritableThreadLocal 的值时,我们将看到输出“Hello from Parent Thread!”。
最后,我们分别在父线程、子线程和主线程中输出 inheritableThreadLocal 的值。由于我们在每个线程中都设置了 inheritableThreadLocal 的值,所以每个线程都将输出不同的值。
请注意,在程序的结尾处,我们调用了 inheritableThreadLocal.remove() 方法来清除 InheritableThreadLocal 对象的值,并释放相关的资源。这是一种良好的习惯,可以避免内存泄漏和数据污染等问题。
3、相关问题
1.请简述Java中的多线程通信机制,并解释一下为什么需要多线程通信?
答:Java中的多线程通信机制是通过使用管道和共享变量来实现的。管道可以用来实现多个线程之间的数据传递和同步,共享变量可以用来实现多个线程之间的数据共享和同步。
2.Java 中,在多个线程之间共享数据的方式主要有以下几种:
1)共享变量:可以将需要共享的变量定义为静态变量或公共变量,然后通过同步控制机制(例如 synchronized 关键字、Lock 接口等)保证多线程访问这些变量时的安全性。
2)ThreadLocal:通过 ThreadLocal 类可以在每个线程中创建独立的变量副本,从而避免了对共享变量的竞争。
3)Callable 和 Future 接口:在子线程执行任务后,可以通过 Callable 和 Future 接口返回结果给主线程。主线程可以通过 Future.get() 方法获取子线程的执行结果,从而完成数据共享。
4)BlockingQueue:可以使用 BlockingQueue 来实现数据共享和通信,生产者线程向 BlockingQueue 中添加数据,消费者线程从队列中获取数据。
5)CyclicBarrier 和 CountDownLatch:可以使用 CyclicBarrier 和 CountDownLatch 等同步工具来协调多个线程之间的操作,从而实现数据共享。