看起来你想学习java多线程的原理。我通常会推荐使用并发队列,但也许你需要使用同步原语自己实现一些东西。
需要了解的基本知识是:
- 并发访问的线程间套利
- 在线程之间发出信号以指示某些事件的变化或即将发生
您将需要第一个让两个线程访问同一条数据而不会互相踩到对方的脚趾,第二个让每个线程知道另一个线程完成了它的工作部分。
正如您在问题正文中指出的那样,算法大纲类似于:
- 线程(1)设置值
- 线程 (1) 告诉线程 (2) 它可以处理数据
- 线程(2)更新值
- 线程 (2) 告诉线程 (1) 它已完成数据处理
- 线程(1)显示结果
如果操作正确,您实际上不需要处理对变量的并发访问,因为每个线程将分别完成其工作,并等待另一个线程的信号来访问数据。
更详细地说,整体执行如下:
- 线程 (2) 等待线程 (1) 信号
- 线程(1)设置值
- 线程 (1) 告诉线程 (2) 它可以处理数据
- 线程 (1) 等待线程 (2) 信号
- 线程(2)更新值
- 线程 (2) 告诉线程 (1) 它已完成数据处理
- 线程(1)显示结果
现在,您可以将线程各自的指令序列分开,以了解每个线程自己需要做什么。
信号量是非常通用的对象,可用于在线程之间发出事件信号,尽管它的接口不是很能说明问题:
- 实例必须初始化为
0
,
acquire
对该方法的调用在语义上与等待事件相同
- 调用
release
将对应于信号触发器
因此,每个线程都必须持有对要操作的变量的引用,以及对同一信号量实例的引用以在 (*) 上同步。
您的程序的下一步可能是将其转换为更通用的生产者消费者设置,其中线程一和线程二处理多个值而不仅仅是一个。这是您需要使用并发队列类的地方。也就是说,鉴于上述解释,您可能希望首先自己实现这样的队列。
编辑:
您的更新表明您希望使用 PipedInputStream 和 PipedOutputStream 作为线程之间的通信媒介。
在此设置中,管道让您的线程自然同步,因为read
输入管道的方法是阻塞的。您将需要为每个线程提供一对输入和输出管道,其中第二个的输入与第connect
一个的输出相结合,反之亦然。
算法变为:
- 线程(2)从输入管道读取(并阻塞直到它接收到它)
- 线程 (1) 计算初始值
- thread (1)
write
将值传给它的输出管道
- 线程 (1) 从其输入管道(和块)读取
- 线程 (2) 从调用返回
read
- 线程 (2) 处理它收到的整数
- 线程 (2) 将新值写回其输出管道
- 线程 (1) 从其返回
read
- 线程(1)打印结果
和前面的算法一样,每个指令序列可以分别在自己的函数中实现。难点可能是将整数从其本机表示来回转换为可以作为字节流读取和写入的整数。这个过程称为序列化和反序列化。
一种方法是使用Integer
类工具与 a 进行转换String
(使用toString
和parseInt
方法调用),然后将字符串本身转换为字节数组以与流一起使用。
该解决方案有点麻烦,尽管它确实有助于理解序列化的概念。幸运的是,Java 让您可以非常轻松地处理序列化。有关详细信息和可能的陷阱,请参阅关于该主题的其他问题。由于它依赖于与上述流方法相同的机制,因此在尝试反序列化尚未序列化的值时,线程将以类似的方式阻塞。
有关详细信息,请参阅管道类的connect、 [read][3] 和 [write][4] 方法。
(*) 我会泄漏 (java) bean:您实际上可以使用任何 java 对象作为信号机制,使用它们上的wait
andnotify
方法,但这对于教程来说会很有趣吗?
[3]: http://docs.oracle.com/javase/6/docs/api/java/io/PipedInputStream.html#read(byte[] , int, int) [4]: http://docs. oracle.com/javase/6/docs/api/java/io/PipedOutputStream.html#write(byte[] , int, int)