Java 如何同步2个线程?
Java how to synchronize 2 threads?
已解决!
我有作业。我很快就会说是关于什么的。我必须从 .txt
文件中读取几个数字,然后将它们相乘。我需要使用线程并仅同步该乘法。我已经这样做了,我的作业到此结束!但是,我想继续创建更复杂的方式,例如:
我有 .txt
个这样的数字:5、6、2、11、24、10、
然后我像这样将它们相乘 5*6*2*11*24*10 .
如何创建 2 个线程,Thread #1
用于数字,Thread #2
用于乘法,并像这样在控制台中打印它们:
Thread #1 running, number is 5
Thread #2 running, multiply is 5
Thread #1 running, number is 6
Thread #2 running, multiply is 30
Thread #1 running, number is 2
Thread #2 running, multiply is 60
我非常感谢任何建议,过去 10 小时以来我一直在做这件事,但仍然无法让它发挥作用。
class MyThread extends Thread {
Thread thread;
MyThread(String name) {
thread = new Thread(this, name);
}
public synchronized void numbers(boolean running) {
if (!running) {
notify();
return;
}
notify();
try {
FileInputStream fs = new FileInputStream("in.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
String line;
int numbers = 0;
while ((line = br.readLine()) != null) {
String[] splitter = line.split("\s");
numbers = Integer.parseInt(splitter[0]);
for (int i = 0; i <= splitter.length - 1; i++) {
numbers = Integer.parseInt(splitter[i]);
System.out.print("\nIn " + thread.getName() + "number is " + numbers + "\t");
Thread.sleep(500);
}
}
} catch (InterruptedException e) {
System.out.println("main thread interrupted");
} catch (IOException e) {
System.out.println("main thread interrupted");
}
}
public synchronized void multiply(boolean running) {
if (!running) {
notify();
return;
}
notify();
try {
FileInputStream fs = new FileInputStream("in.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
String line;
int numbers = 0;
int multiply = 1;
while ((line = br.readLine()) != null) {
String[] splitter = line.split("\s");
numbers = Integer.parseInt(splitter[0]);
for (int i = 0; i <= splitter.length - 1; i++) {
numbers = Integer.parseInt(splitter[i]);
multiply = multiply * numbers;
System.out.print("\nIn " + thread.getName() + " multiply is " + multiply + "\t");
Thread.sleep(500);
}
}
} catch (InterruptedException e) {
System.out.println("main thread interrupted");
} catch (IOException e) {
System.out.println("main thread interrupted");
}
}
synchronized public void run() {
if (thread.getName().compareTo("Thread #1 ") == 0) {
for (int i = 0; i < 1; i++)
this.numbers(true);
this.numbers(false);
} else {
for (int i = 0; i < 1; i++)
this.multiply(true);
this.multiply(false);
}
}
}
我的代码如下所示:
主要我是这样调用的:
MyThread mt1 = new MyThread("Thread #1 ");
MyThread mt2 = new MyThread("Thread #2 ");
mt1.start();
mt2.start();
此刻,我的输出是这样的:
In Thread #2 multiply is 5
In Thread #1 number is 5
In Thread #1 number is 6
In Thread #2 multiply is 6
In Thread #2 multiply is 30
In Thread #1 number is 2
In Thread #1 number is 11
In Thread #2 multiply is 660
In Thread #2 multiply is 15840
In Thread #1 number is 24
不清楚您要做什么。代码中有一些我想强调的明显错误(因此写了这个答案),但我无法回答这个问题,因为代码似乎按照它写的去做:它运行 2 个线程,都从同一个文件,读取输出结果略有不同
现在解决问题:
1) 如果你正在扩展线程,你不应该在其中有一个线程字段。基本上你可以替换 thread = new Thread(this ,name);与超级(名字)。
2) 你的同步没有做任何事情。同步使方法在您进入方法时进入监视器(本质上是获取对象锁),并在方法完成时释放它。您的两个线程是 2 个不同的实例,彼此之间不共享任何数据,因此同步没有做任何事情。
按照您编写代码的方式,这两个线程并不是真正的 "connected",它们不共享任何内存。他们读取同一个文件,仅此而已——没有共享内存。根据我的猜测,这个想法宁愿有一个 "producer" 线程从文件中读取数据,还有一个 "consumer" 线程获取第一个线程读取的数据并执行乘法。第二个线程不应读取文件。
您可以使用共享的 AtomicInteger 编写一些内容:当为空(null)时,"producer" 线程将其设置为已读取的内容;当非空时,"consumer" 线程读取它,将其重置为空,并且可以 运行 它的乘法。
问题是您正试图对这两项任务使用一种实现。我建议创建 ReadThread
来读取输入文件,并创建 MultiplyThread
来等待某些事件并乘以数字。他们还需要分享一些号码集合(例如,参见 ConcurrentLinkedQueue)。
所以ReadThread
从文件中读取一个数字,将其添加到队列中。同时 MultiplyThread
等待任何东西出现在同一个队列中,当这种情况发生时,将新数字乘以前一个。设计上也会有改进,因为我们可以用 AddThread
代替 MultiplyThread
来计算数字的总和。
然而,您的实施试图在一个 class 中完成这两项任务,这大大增加了复杂性。还要尝试摆脱 synchronized
和 Thread.sleep
语句,在你的情况下它们会降低性能并且使用多线程没有意义。
这是我建议的方法的示例实现。
首先是ReadThread
。它有一个队列,其中包含必须处理的数字。我已经简化了从文件中读取数字的过程,您可以将其替换为您的阅读实现。
class ReadThread implements Runnable {
private final String filename;
private final ConcurrentLinkedQueue<Integer> queue;
public ReadThread(ConcurrentLinkedQueue<Integer> queue, String filename) {
this.queue = queue;
this.filename = filename;
}
public void run() {
try {
FileInputStream fs = new FileInputStream(filename);
Scanner scanner = new Scanner(fs);
while (scanner.hasNextInt()) {
int number = scanner.nextInt();
System.out.println("ReadThread read " + number);
queue.add(number);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
和 MultiplyThread
。在这里,我们从队列中取出数字并将其乘以存储先前值的 result
。线程生命周期存在问题——我们不知道什么时候应该停止它。所以我使用了简单的 active
标志。它告诉线程何时停止。
class MultiplyThread implements Runnable {
private boolean active = true;
private Integer result = 1;
private final Queue<Integer> queue;
public MultiplyThread(ConcurrentLinkedQueue<Integer> queue) {
this.queue = queue;
}
public void run() {
while (isActive()) {
Integer number = queue.poll();
if (number != null) {
result *= number;
System.out.println("MultiplyThread current result is " + result);
}
}
}
public synchronized void stop() {
active = false;
}
public synchronized boolean isActive() {
return active;
}
}
这是最后一部分。由于 MultiplyThread
中断,它比你的更复杂。
public static void main(String[] args) throws InterruptedException {
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
ReadThread readThread = new ReadThread(queue, "numbers.txt");
MultiplyThread multiplyThread = new MultiplyThread(queue);
Thread reader = new Thread(readThread);
Thread multiplicator = new Thread(multiplyThread);
multiplicator.start();
reader.start();
reader.join();
multiplyThread.stop();
multiplicator.join();
}
程序的结果
ReadThread read 1
ReadThread read 2
MultiplyThread current result is 1
MultiplyThread current result is 2
ReadThread read 3
MultiplyThread current result is 6
ReadThread read 4
MultiplyThread current result is 24
ReadThread read 5
MultiplyThread current result is 120
ReadThread read 6
MultiplyThread current result is 720
ReadThread read 7
MultiplyThread current result is 5040
您可以看到线程正在并发工作,ReadThread
不会等待 MultiplyThread
计算所有先前值的结果。
已解决!
我有作业。我很快就会说是关于什么的。我必须从 .txt
文件中读取几个数字,然后将它们相乘。我需要使用线程并仅同步该乘法。我已经这样做了,我的作业到此结束!但是,我想继续创建更复杂的方式,例如:
我有 .txt
个这样的数字:5、6、2、11、24、10、
然后我像这样将它们相乘 5*6*2*11*24*10 .
如何创建 2 个线程,Thread #1
用于数字,Thread #2
用于乘法,并像这样在控制台中打印它们:
Thread #1 running, number is 5
Thread #2 running, multiply is 5
Thread #1 running, number is 6
Thread #2 running, multiply is 30
Thread #1 running, number is 2
Thread #2 running, multiply is 60
我非常感谢任何建议,过去 10 小时以来我一直在做这件事,但仍然无法让它发挥作用。
class MyThread extends Thread {
Thread thread;
MyThread(String name) {
thread = new Thread(this, name);
}
public synchronized void numbers(boolean running) {
if (!running) {
notify();
return;
}
notify();
try {
FileInputStream fs = new FileInputStream("in.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
String line;
int numbers = 0;
while ((line = br.readLine()) != null) {
String[] splitter = line.split("\s");
numbers = Integer.parseInt(splitter[0]);
for (int i = 0; i <= splitter.length - 1; i++) {
numbers = Integer.parseInt(splitter[i]);
System.out.print("\nIn " + thread.getName() + "number is " + numbers + "\t");
Thread.sleep(500);
}
}
} catch (InterruptedException e) {
System.out.println("main thread interrupted");
} catch (IOException e) {
System.out.println("main thread interrupted");
}
}
public synchronized void multiply(boolean running) {
if (!running) {
notify();
return;
}
notify();
try {
FileInputStream fs = new FileInputStream("in.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
String line;
int numbers = 0;
int multiply = 1;
while ((line = br.readLine()) != null) {
String[] splitter = line.split("\s");
numbers = Integer.parseInt(splitter[0]);
for (int i = 0; i <= splitter.length - 1; i++) {
numbers = Integer.parseInt(splitter[i]);
multiply = multiply * numbers;
System.out.print("\nIn " + thread.getName() + " multiply is " + multiply + "\t");
Thread.sleep(500);
}
}
} catch (InterruptedException e) {
System.out.println("main thread interrupted");
} catch (IOException e) {
System.out.println("main thread interrupted");
}
}
synchronized public void run() {
if (thread.getName().compareTo("Thread #1 ") == 0) {
for (int i = 0; i < 1; i++)
this.numbers(true);
this.numbers(false);
} else {
for (int i = 0; i < 1; i++)
this.multiply(true);
this.multiply(false);
}
}
}
我的代码如下所示:
主要我是这样调用的:
MyThread mt1 = new MyThread("Thread #1 ");
MyThread mt2 = new MyThread("Thread #2 ");
mt1.start();
mt2.start();
此刻,我的输出是这样的:
In Thread #2 multiply is 5
In Thread #1 number is 5
In Thread #1 number is 6
In Thread #2 multiply is 6
In Thread #2 multiply is 30
In Thread #1 number is 2
In Thread #1 number is 11
In Thread #2 multiply is 660
In Thread #2 multiply is 15840
In Thread #1 number is 24
不清楚您要做什么。代码中有一些我想强调的明显错误(因此写了这个答案),但我无法回答这个问题,因为代码似乎按照它写的去做:它运行 2 个线程,都从同一个文件,读取输出结果略有不同
现在解决问题:
1) 如果你正在扩展线程,你不应该在其中有一个线程字段。基本上你可以替换 thread = new Thread(this ,name);与超级(名字)。
2) 你的同步没有做任何事情。同步使方法在您进入方法时进入监视器(本质上是获取对象锁),并在方法完成时释放它。您的两个线程是 2 个不同的实例,彼此之间不共享任何数据,因此同步没有做任何事情。
按照您编写代码的方式,这两个线程并不是真正的 "connected",它们不共享任何内存。他们读取同一个文件,仅此而已——没有共享内存。根据我的猜测,这个想法宁愿有一个 "producer" 线程从文件中读取数据,还有一个 "consumer" 线程获取第一个线程读取的数据并执行乘法。第二个线程不应读取文件。
您可以使用共享的 AtomicInteger 编写一些内容:当为空(null)时,"producer" 线程将其设置为已读取的内容;当非空时,"consumer" 线程读取它,将其重置为空,并且可以 运行 它的乘法。
问题是您正试图对这两项任务使用一种实现。我建议创建 ReadThread
来读取输入文件,并创建 MultiplyThread
来等待某些事件并乘以数字。他们还需要分享一些号码集合(例如,参见 ConcurrentLinkedQueue)。
所以ReadThread
从文件中读取一个数字,将其添加到队列中。同时 MultiplyThread
等待任何东西出现在同一个队列中,当这种情况发生时,将新数字乘以前一个。设计上也会有改进,因为我们可以用 AddThread
代替 MultiplyThread
来计算数字的总和。
然而,您的实施试图在一个 class 中完成这两项任务,这大大增加了复杂性。还要尝试摆脱 synchronized
和 Thread.sleep
语句,在你的情况下它们会降低性能并且使用多线程没有意义。
这是我建议的方法的示例实现。
首先是ReadThread
。它有一个队列,其中包含必须处理的数字。我已经简化了从文件中读取数字的过程,您可以将其替换为您的阅读实现。
class ReadThread implements Runnable {
private final String filename;
private final ConcurrentLinkedQueue<Integer> queue;
public ReadThread(ConcurrentLinkedQueue<Integer> queue, String filename) {
this.queue = queue;
this.filename = filename;
}
public void run() {
try {
FileInputStream fs = new FileInputStream(filename);
Scanner scanner = new Scanner(fs);
while (scanner.hasNextInt()) {
int number = scanner.nextInt();
System.out.println("ReadThread read " + number);
queue.add(number);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
和 MultiplyThread
。在这里,我们从队列中取出数字并将其乘以存储先前值的 result
。线程生命周期存在问题——我们不知道什么时候应该停止它。所以我使用了简单的 active
标志。它告诉线程何时停止。
class MultiplyThread implements Runnable {
private boolean active = true;
private Integer result = 1;
private final Queue<Integer> queue;
public MultiplyThread(ConcurrentLinkedQueue<Integer> queue) {
this.queue = queue;
}
public void run() {
while (isActive()) {
Integer number = queue.poll();
if (number != null) {
result *= number;
System.out.println("MultiplyThread current result is " + result);
}
}
}
public synchronized void stop() {
active = false;
}
public synchronized boolean isActive() {
return active;
}
}
这是最后一部分。由于 MultiplyThread
中断,它比你的更复杂。
public static void main(String[] args) throws InterruptedException {
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
ReadThread readThread = new ReadThread(queue, "numbers.txt");
MultiplyThread multiplyThread = new MultiplyThread(queue);
Thread reader = new Thread(readThread);
Thread multiplicator = new Thread(multiplyThread);
multiplicator.start();
reader.start();
reader.join();
multiplyThread.stop();
multiplicator.join();
}
程序的结果
ReadThread read 1
ReadThread read 2
MultiplyThread current result is 1
MultiplyThread current result is 2
ReadThread read 3
MultiplyThread current result is 6
ReadThread read 4
MultiplyThread current result is 24
ReadThread read 5
MultiplyThread current result is 120
ReadThread read 6
MultiplyThread current result is 720
ReadThread read 7
MultiplyThread current result is 5040
您可以看到线程正在并发工作,ReadThread
不会等待 MultiplyThread
计算所有先前值的结果。