Java 3个线程按顺序打印备用值
我试图创建一个实现,其中多个线程打印序列的备用值。这里thread1将打印1,4,7 thread2将打印2,5,8 thread3将打印3,6,9。我使用的是原子整数和模函数 在第一个线程打印1,4,7,而第二个线程打印2,5,8,第三个线程打印3,6,9的意义上,下面的实现工作得很好,但问题是没有保持顺序,即输出可能类似于1,3,2,4,5,7,8,6,9,而我希望保持顺序,因为正确的线程可以打印这些值。 一个条件是我不想使用同步。[仅用于学习目的]Java 3个线程按顺序打印备用值,java,multithreading,Java,Multithreading,我试图创建一个实现,其中多个线程打印序列的备用值。这里thread1将打印1,4,7 thread2将打印2,5,8 thread3将打印3,6,9。我使用的是原子整数和模函数 在第一个线程打印1,4,7,而第二个线程打印2,5,8,第三个线程打印3,6,9的意义上,下面的实现工作得很好,但问题是没有保持顺序,即输出可能类似于1,3,2,4,5,7,8,6,9,而我希望保持顺序,因为正确的线程可以打印这些值。 一个条件是我不想使用同步。[仅用于学习目的] import java.util.con
import java.util.concurrent.atomic.AtomicInteger;
public class ThreeThreadsOrderedLockLess {
AtomicInteger sharedOutput = new AtomicInteger(0);
public static void main(String args[]) {
ThreeThreadsOrderedLockLess t = new ThreeThreadsOrderedLockLess();
ThreadTasks t1 = t.new ThreadTasks(0);
ThreadTasks t2 = t.new ThreadTasks(1);
ThreadTasks t3 = t.new ThreadTasks(2);
Thread ts1 = new Thread(t1);
Thread ts2 = new Thread(t2);
Thread ts3 = new Thread(t3);
ts1.start();
ts2.start();
ts3.start();
}
private class ThreadTasks implements Runnable {
private final int threadPosition;
public ThreadTasks(int threadPosition) {
super();
this.threadPosition = threadPosition;
}
@Override
public void run() {
while (sharedOutput.get() < 9) {
if (sharedOutput.get() % 3 == this.threadPosition) {
System.out.println("Printing output for Thread: "
+ this.threadPosition + " "
+ sharedOutput.incrementAndGet());
}
}
}
}
}
这是因为每个线程的时间片由操作系统决定。因此,线程x可能会增加共享编号,但在打印之前,时间片会传递给下一个线程y,该线程现在读取共享编号,并在增加后打印它,假设线程y比线程x有更多的时间来增加和打印共享编号
这是因为每个线程的时间片由操作系统决定。因此,线程x可能会增加共享编号,但在打印之前,时间片会传递给下一个线程y,该线程现在读取共享编号,并在增加后打印它,假设线程y比线程x有更多的时间来增加和打印共享编号
.您应该先打印,然后递增:
int value = sharedOutput.get() + 1;
System.out.println("Printing output for Thread: "
+ this.threadPosition + " "
+ value);
sharedOutput.incrementAndGet();
也就是说,所有线程都忙于循环,这将导致100%的CPU使用率。您应该同步线程。您应该先打印,然后递增:
int value = sharedOutput.get() + 1;
System.out.println("Printing output for Thread: "
+ this.threadPosition + " "
+ value);
sharedOutput.incrementAndGet();
也就是说,所有线程都忙于循环,这将导致100%的CPU使用率。您应该改为同步线程。使用wait、notify、notify Java的所有方法。
你也可以看看这些方法中的这个
希望这将有助于解决您的问题
此示例的输出如下所示
Put:1
得到:1
Put:2
得到:2
Put:3
得到:3
Put:4
得到:4
Put:5
Got:5使用wait、notify、notifyJava的所有方法。
你也可以看看这些方法中的这个
希望这将有助于解决您的问题
此示例的输出如下所示
Put:1
得到:1
Put:2
得到:2
Put:3
得到:3
Put:4
得到:4
Put:5
得到:5这应该可以:
package com.sid;
import java.util.concurrent.atomic.AtomicInteger;
public class NumberSequence {
private AtomicInteger sharedOutput = new AtomicInteger(0);
private Object object = new Object();
public static void main(String args[]) {
NumberSequence t = new NumberSequence();
ThreadTasks t1 = t.new ThreadTasks(0);
ThreadTasks t2 = t.new ThreadTasks(1);
ThreadTasks t3 = t.new ThreadTasks(2);
Thread ts1 = new Thread(t1);
Thread ts2 = new Thread(t2);
Thread ts3 = new Thread(t3);
ts1.start();
ts2.start();
ts3.start();
}
private class ThreadTasks implements Runnable {
private final int threadPosition;
public ThreadTasks(int threadPosition) {
super();
this.threadPosition = threadPosition;
}
@Override
public void run() {
while (sharedOutput.get() < 10) {
synchronized (object) {
if (sharedOutput.get() % 3 == this.threadPosition) {
if(sharedOutput.get() < 10)
System.out.println("Printing output for Thread: "
+ this.threadPosition + " "
+ sharedOutput.incrementAndGet());
}
}
}
}
}
}
这应该起作用:
package com.sid;
import java.util.concurrent.atomic.AtomicInteger;
public class NumberSequence {
private AtomicInteger sharedOutput = new AtomicInteger(0);
private Object object = new Object();
public static void main(String args[]) {
NumberSequence t = new NumberSequence();
ThreadTasks t1 = t.new ThreadTasks(0);
ThreadTasks t2 = t.new ThreadTasks(1);
ThreadTasks t3 = t.new ThreadTasks(2);
Thread ts1 = new Thread(t1);
Thread ts2 = new Thread(t2);
Thread ts3 = new Thread(t3);
ts1.start();
ts2.start();
ts3.start();
}
private class ThreadTasks implements Runnable {
private final int threadPosition;
public ThreadTasks(int threadPosition) {
super();
this.threadPosition = threadPosition;
}
@Override
public void run() {
while (sharedOutput.get() < 10) {
synchronized (object) {
if (sharedOutput.get() % 3 == this.threadPosition) {
if(sharedOutput.get() < 10)
System.out.println("Printing output for Thread: "
+ this.threadPosition + " "
+ sharedOutput.incrementAndGet());
}
}
}
}
}
}
正确的同步将帮助您获得清晰的答案。我已经改进了实施,你应该解决你的问题
int threadId;
int moduluos;
int numOfThreads;
public ThreadTasks(int id, int nubOfThreads) {
threadId = id;
this.numOfThreads = nubOfThreads;
moduluos = threadId%numOfThreads;
}
public void run() {
print();
}
private void print() {
try {
while (true) {
synchronized (monitor) {
if (number.get() % numOfThreads != moduluos) {
monitor.wait();
} else {
System.out.println("ThreadId [" + threadId
+ "] printing -->"
+ number.getAndIncrement());
monitor.notifyAll();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
正确的同步将帮助您获得清晰的答案。我已经改进了实施,你应该解决你的问题
int threadId;
int moduluos;
int numOfThreads;
public ThreadTasks(int id, int nubOfThreads) {
threadId = id;
this.numOfThreads = nubOfThreads;
moduluos = threadId%numOfThreads;
}
public void run() {
print();
}
private void print() {
try {
while (true) {
synchronized (monitor) {
if (number.get() % numOfThreads != moduluos) {
monitor.wait();
} else {
System.out.println("ThreadId [" + threadId
+ "] printing -->"
+ number.getAndIncrement());
monitor.notifyAll();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用阻塞队列可以更好地实现这一点。定义持有阻塞队列的工作进程。工人在队列上等待,直到队列中收到一个数字。它打印接收到的数字,增加数字,并将其传递给链中的下一个工人。请参阅完整的解决方案 使用阻塞队列可以更好地实现这一点。定义持有阻塞队列的工作进程。工人在队列上等待,直到队列中收到一个数字。它打印接收到的数字,增加数字,并将其传递给链中的下一个工人。请参阅完整的解决方案 下面的代码片段将按顺序打印数字,所有线程将在任务完成后优雅地终止。 使用AtomicInteger,它对于打印数字是线程安全的,并且相同的逻辑可以应用于打印任何带有任意线程数的数字 import java.util.concurrent.atomic.AtomicInteger; public class PrintNumSequence { public static void main(String[] args) { AtomicInteger atomicInteger = new AtomicInteger(0); new NumPrinter(atomicInteger, 0).start();// thread0 new NumPrinter(atomicInteger, 1).start();// thread1 new NumPrinter(atomicInteger, 2).start();// thread2 } } class NumPrinter extends Thread { private AtomicInteger atomicInteger; private int threadNum; public NumPrinter(AtomicInteger atomicInteger, int threadNum) { this.atomicInteger = atomicInteger; this.threadNum = threadNum; } @Override public void run() { int num = atomicInteger.intValue(); do { synchronized (atomicInteger) { num = atomicInteger.intValue(); // If number is 9 then stop. if (num > 9) { atomicInteger.notifyAll(); break; } // 3 is number of threads if ((num % 3) == threadNum) { System.out.println("Thread-" + threadNum + " -->" + num); num = atomicInteger.incrementAndGet(); } atomicInteger.notifyAll(); try { atomicInteger.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } while (true); } }
下面的代码片段将按顺序打印数字,所有线程将在任务完成后优雅地终止。 使用AtomicInteger,它对于打印数字是线程安全的,并且相同的逻辑可以应用于打印任何带有任意线程数的数字 import java.util.concurrent.atomic.AtomicInteger; public class PrintNumSequence { public static void main(String[] args) { AtomicInteger atomicInteger = new AtomicInteger(0); new NumPrinter(atomicInteger, 0).start();// thread0 new NumPrinter(atomicInteger, 1).start();// thread1 new NumPrinter(atomicInteger, 2).start();// thread2 } } class NumPrinter extends Thread { private AtomicInteger atomicInteger; private int threadNum; public NumPrinter(AtomicInteger atomicInteger, int threadNum) { this.atomicInteger = atomicInteger; this.threadNum = threadNum; } @Override public void run() { int num = atomicInteger.intValue(); do { synchronized (atomicInteger) { num = atomicInteger.intValue(); // If number is 9 then stop. if (num > 9) { atomicInteger.notifyAll(); break; } // 3 is number of threads if ((num % 3) == threadNum) { System.out.println("Thread-" + threadNum + " -->" + num); num = atomicInteger.incrementAndGet(); } atomicInteger.notifyAll(); try { atomicInteger.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } while (true); } }
我把代码打印1-100使用5线程。可以使用任意数量的线程以循环方式打印输出 基本概念是锁定一个对象并通知另一个对象以执行值的打印
public class PrintOneToHundredUsing5Threads {
public static void main(String[] args) {
List<Object> objList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
objList.add(new Object());
}
for (int i = 0; i < 5; i++) {
Thread t = new Thread(new PrintThread(objList.get(i), objList.get((i + 1) % 5)));
t.setName("Thread" + i);
t.start();
}
}
}
class PrintThread implements Runnable {
Object current;
Object next;
volatile static int i = 1;
PrintThread(Object cur, Object next) {
this.current = cur;
this.next = next;
}
@Override
public void run() {
for (; i <= 100;) {
synchronized (current) {
synchronized (next) {
next.notify();
System.out.println(Thread.currentThread().getName() + " Value : " + i++);
}
try {
current.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
我把代码打印1-100使用5线程。可以使用任意数量的线程以循环方式打印输出 基本概念是锁定一个对象并通知另一个对象以执行值的打印
public class PrintOneToHundredUsing5Threads {
public static void main(String[] args) {
List<Object> objList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
objList.add(new Object());
}
for (int i = 0; i < 5; i++) {
Thread t = new Thread(new PrintThread(objList.get(i), objList.get((i + 1) % 5)));
t.setName("Thread" + i);
t.start();
}
}
}
class PrintThread implements Runnable {
Object current;
Object next;
volatile static int i = 1;
PrintThread(Object cur, Object next) {
this.current = cur;
this.next = next;
}
@Override
public void run() {
for (; i <= 100;) {
synchronized (current) {
synchronized (next) {
next.notify();
System.out.println(Thread.currentThread().getName() + " Value : " + i++);
}
try {
current.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
您可以使用以下代码使用多个线程打印序列号-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ThreadCall extends Thread {
private BlockingQueue<Integer> bq = new ArrayBlockingQueue<Integer>(10);
private ThreadCall next;
public void setNext(ThreadCall t) {
this.next = t;
}
public void addElBQ(int a) {
this.bq.add(a);
}
public ThreadCall(String name) {
this.setName(name);
}
@Override
public void run() {
int x = 0;
while(true) {
try {
x = 0;
x = bq.take();
if (x!=0) {
System.out.println(Thread.currentThread().getName() + " =>" + x);
if (x >= 100) System.exit(0); // Need to stop all running threads
next.addElBQ(x+1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int THREAD_COUNT = 10;
List<ThreadCall> listThread = new ArrayList<>();
for (int i=1; i<=THREAD_COUNT; i++) {
listThread.add(new ThreadCall("Thread " + i));
}
for (int i = 0; i < listThread.size(); i++) {
if (i == listThread.size()-1) {
listThread.get(i).setNext(listThread.get(0));
}
else listThread.get(i).setNext(listThread.get(i+1));
}
listThread.get(0).addElBQ(1);
for (int i = 0; i < listThread.size(); i++) {
listThread.get(i).start();
}
}
}
希望这能解决您的问题。您可以使用以下代码使用多线程打印序列号-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ThreadCall extends Thread {
private BlockingQueue<Integer> bq = new ArrayBlockingQueue<Integer>(10);
private ThreadCall next;
public void setNext(ThreadCall t) {
this.next = t;
}
public void addElBQ(int a) {
this.bq.add(a);
}
public ThreadCall(String name) {
this.setName(name);
}
@Override
public void run() {
int x = 0;
while(true) {
try {
x = 0;
x = bq.take();
if (x!=0) {
System.out.println(Thread.currentThread().getName() + " =>" + x);
if (x >= 100) System.exit(0); // Need to stop all running threads
next.addElBQ(x+1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int THREAD_COUNT = 10;
List<ThreadCall> listThread = new ArrayList<>();
for (int i=1; i<=THREAD_COUNT; i++) {
listThread.add(new ThreadCall("Thread " + i));
}
for (int i = 0; i < listThread.size(); i++) {
if (i == listThread.size()-1) {
listThread.get(i).setNext(listThread.get(0));
}
else listThread.get(i).setNext(listThread.get(i+1));
}
listThread.get(0).addElBQ(1);
for (int i = 0; i < listThread.size(); i++) {
listThread.get(i).start();
}
}
}
希望这能解决您的问题。ThreadSynchronization类可用于按顺序打印“n”个线程之间的数字。 逻辑是在每个连续线程之间创建一个公共对象,并使用“等待”、“通知”按顺序打印数字。 注意:最后一个线程将与第一个线程共享一个对象 在运行程序之前,可以更改“maxThreads”值以增加或减少程序中的线程数
import java.util.ArrayList;
import java.util.List;
public class ThreadSynchronization {
public static int i = 1;
public static final int maxThreads = 10;
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < maxThreads; i++) {
list.add(new Object());
}
Object currObject = list.get(maxThreads - 1);
for (int i = 0; i < maxThreads; i++) {
Object nextObject = list.get(i);
RunnableClass1 a = new RunnableClass1(currObject, nextObject, i == 0 ? true : false);
Thread th = new Thread(a);
th.setName("Thread - " + (i + 1));
th.start();
currObject = list.get(i);
}
}
}
class RunnableClass implements Runnable {
private Object currObject;
private Object nextObject;
private boolean firstThread;
public RunnableClass(Object currObject, Object nextObject, boolean first) {
this.currObject = currObject;
this.nextObject = nextObject;
this.firstThread = first;
}
@Override
public void run() {
int i = 0;
try {
if (firstThread) {
Thread.sleep(5000);
firstThread = false;
System.out.println(Thread.currentThread().getName() + " - " + ThreadSynchronization.i++);
synchronized (nextObject) {
nextObject.notify();
}
}
while (i++ < Integer.MAX_VALUE) {
synchronized (currObject) {
currObject.wait();
}
System.out.println(Thread.currentThread().getName() + " - " + ThreadSynchronization.i++);
Thread.sleep(1000);
synchronized (nextObject) {
nextObject.notify();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ThreadSynchronization类可以是 用于按顺序打印“n”个线程之间的数字。 逻辑是在每个连续线程之间创建一个公共对象,并使用“等待”、“通知”按顺序打印数字。 注意:最后一个线程将与第一个线程共享一个对象 在运行程序之前,可以更改“maxThreads”值以增加或减少程序中的线程数
import java.util.ArrayList;
import java.util.List;
public class ThreadSynchronization {
public static int i = 1;
public static final int maxThreads = 10;
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < maxThreads; i++) {
list.add(new Object());
}
Object currObject = list.get(maxThreads - 1);
for (int i = 0; i < maxThreads; i++) {
Object nextObject = list.get(i);
RunnableClass1 a = new RunnableClass1(currObject, nextObject, i == 0 ? true : false);
Thread th = new Thread(a);
th.setName("Thread - " + (i + 1));
th.start();
currObject = list.get(i);
}
}
}
class RunnableClass implements Runnable {
private Object currObject;
private Object nextObject;
private boolean firstThread;
public RunnableClass(Object currObject, Object nextObject, boolean first) {
this.currObject = currObject;
this.nextObject = nextObject;
this.firstThread = first;
}
@Override
public void run() {
int i = 0;
try {
if (firstThread) {
Thread.sleep(5000);
firstThread = false;
System.out.println(Thread.currentThread().getName() + " - " + ThreadSynchronization.i++);
synchronized (nextObject) {
nextObject.notify();
}
}
while (i++ < Integer.MAX_VALUE) {
synchronized (currObject) {
currObject.wait();
}
System.out.println(Thread.currentThread().getName() + " - " + ThreadSynchronization.i++);
Thread.sleep(1000);
synchronized (nextObject) {
nextObject.notify();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出:
打印值:0,按线程:线程-0打印值:1,按
线程:线程1打印值:3,按线程:线程0
打印值:2,按线程:线程-2打印值:4,按
线程:线程1打印值:6,按线程:线程0
打印值:5,按线程:线程-2打印值:7,按
线程:线程1打印值:9,按线程:线程0
打印值:8,按线程:线程2
输出:
打印值:0,按线程:线程-0打印值:1,按
线程:线程1打印值:3,按线程:线程0
打印值:2,按线程:线程-2打印值:4,按
线程:线程1打印值:6,按线程:线程0
打印值:5,按线程:线程-2打印值:7,按
线程:线程1打印值:9,按线程:线程0
打印值:8,按线程:线程2
如果不使用某种形式的同步,那么当然会发生这种情况!如果您想要串行行为,请不要使用线程。@Eyal:正如我提到的,要保持正确的序列shld,即输出shld为1,2,3,4,5,6,7,8,9。如果您不使用某种形式的同步,那么当然会发生这种情况!如果您想要串行行为,请不要使用线程。@Eyal:正如我提到的,应保持正确的顺序,即输出shld为1,2,3,4,5,6,7,8,9。我已经说过我不想使用同步!!所以没有锁意味着等待通知不在图片中。我已经声明我不想使用同步!!所以没有锁意味着等待通知不在画面中。完美。对我来说效果很好。在sysout中使用incrementAndGet有什么不同?在原始代码中,incrementAndGet被调用。然后将返回的值与输出消息的其余部分连接起来。然后只打印消息。因此,从增量到打印消息之间有很长一段时间,另一个线程会看到AtomicInteger的新值。但是,递增和获取原子不是吗?是的,它是原子的,那又怎样?它仍然在执行打印之前执行。因此其他线程可以看到新的值,并且可以在第一个线程之前打印它们的行。对我来说效果很好。在sysout中使用incrementAndGet有什么不同?在原始代码中,incrementAndGet被调用。然后将返回的值与输出消息的其余部分连接起来。然后只打印消息。因此,从增量到打印消息之间有很长一段时间,另一个线程会看到AtomicInteger的新值。但是,递增和获取原子不是吗?是的,它是原子的,那又怎样?它仍然在执行打印之前执行。因此,其他线程可以看到新的值,并可以在第一个线程之前打印它们的行。请您详细说明您的答案,并添加一点关于您提供的解决方案的说明。请您详细说明您的答案,并添加一点关于您提供的解决方案的说明,好吗?