Java中不同的线程间数据怎么通信

寻技术 JAVA编程 2023年10月03日 120

本文小编为大家详细介绍“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 等同步工具来协调多个线程之间的操作,从而实现数据共享。

关闭

用微信“扫一扫”