Как переключаться между двумя потоками вперед и назад
У меня есть два метода в двух разных классах, как это
public class ClassX implements Runnable {
public void methodAandB() {
for(int i=0;i<10;i++) {
System.out.println("This is A and B ");
}
}
@Override
public void run() {
methodAandB();
}
}
public class ClassY implements Runnable {
public void methodAorB() {
for(int i=0;i<10;i++) {
System.out.println("This is A or B");
}
}
@Override
public void run() {
methodAorB(a);
}
}
Тема t1 вызывает methodAandB()
,
Тема Т2 вызывает methodAorB()
,
Можно ли переключаться между этими двумя потоками после каждой итерации цикла в методах?
Я хочу получить вывод, как это:
Это А и Б
Это А или Б
Это А и Б
Это А или Б
Это А и Б
Это А или Б
Это А и Б
Это А или Б
5 ответов
Лучший пример триггера между потоками:
Имеется два массива типа int (четный и нечетный), 2 потока печатают свои числа в естественном порядке.
package com.rough;
public class ThreadsBehaviour {
static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
int a[] = {1,3,5,7,9};
int b[] = {2,4,6,8,10};
Thread odd = new Thread(new Looper(a, lock));
Thread even = new Thread(new Looper(b, lock));
odd.start();
even.start();
}
}
class Looper implements Runnable
{
int a[];
Object lock;
public Looper(int a[], Object lock)
{
this.a = a;
this.lock = lock;
}
@Override
public void run() {
for(int i = 0; i < a.length; i++)
{
synchronized(lock)
{
System.out.print(a[i]);
try
{
lock.notify();
if(i == (a.length - 1))
{
break;
}
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Вы можете достичь этого просто с помощью общих переменных. Я реализовал и проверил проблему. код ниже
класс X
public class ClassX implements Runnable {
public void methodAandB() {
for(int i=0;i<10;i++) {
while(GlobalClass.isClassXdone)
{}
System.out.println("This is A and B ");
GlobalClass.isClassXdone = true;
GlobalClass.isClassYdone = false;
}}
@Override
public void run() {
methodAandB(); } }
классный
открытый класс ClassY реализует Runnable {
public void methodAorB() {
for(int i=0;i<10;i++) {
while(GlobalClass.isClassYdone)
{}
System.out.println("This is A or B ");
GlobalClass.isClassYdone = true;
GlobalClass.isClassXdone = false;}}
@Override
public void run() {
methodAorB();}}
Определение общей переменной
public class GlobalClass {
public static boolean isClassXdone = false ;
public static boolean isClassYdone = false ;
}
Вы можете просто запустить поток, используя t1.start и t2.start, чтобы получить желаемый результат
Thread t1 = new Thread(new ClassX());
Thread t2 = new Thread(new ClassY());
t1.start();
t2.start();
Я знаю, что уже поздно отвечать на это. Но только вчера я сталкивался с этим вопросом. Так что, думаю, никогда не поздно..;)
Решение, как упомянуто @afsantos, заключается в наличии общего объекта между двумя потоками и реализации взаимного исключения общего объекта. Общий объект может быть альтернативно заблокирован двумя потоками. Две возможные реализации заключаются в следующем. На самом деле это больше похоже на расширение решения @afsantos. Его работа настоящим признана.
Решение 1. План объекта, который будет использоваться совместно, выглядит следующим образом.
public class MutEx {
public int whoGoes, howMany;
public MutEx(int whoGoes, int howMany) {
this.whoGoes = whoGoes;
this.howMany = howMany;
}
public synchronized void switchTurns(){
this.whoGoes = (this.whoGoes + 1) % 2;
notifyAll();
}
public synchronized void waitForTurn(int id) throws InterruptedException{
while(this.whoGoes != id)
wait();
}
}
Затем вы можете реализовать ClassX следующим образом.
public class ClassX implements Runnable {
private final int MY_ID;
private final MutEx MUT_EX;
public ThreadOne(int MY_ID, MutEx MUT_EX) {
this.MY_ID = MY_ID;
this.MUT_EX = MUT_EX;
}
@Override
public void run(){
this.doTheWork();
}
public void doTheWork(){
for(int i = 0; i < 10; i++){
try {
MUT_EX.waitForMyTurn(MY_ID);
System.out.println("This is A and B");
MUT_EX.switchTurns();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ClassY также будет таким же, с любыми различиями, которые вам нужны. Затем в вызове (то есть в основном методе)
public static void main(String[] args) {
MutEx mutEx = new MutEx(0, 2);
Thread t1 = new Thread(new ClassX(0, mutEx);
Thread t2 = new Thread(new ClassY(1, mutEx));
t1.start();
t2.start();
}
Вуаля! У вас есть два потока, чередуя каждый, как вам нужно.
Решение 2. В качестве альтернативы вы можете реализовать ClassX и ClassY следующим образом.
public class ClassX extends Thread{
Здесь вы подкласс java.lang.Thread
реализовать ваше требование. Для этого нужно изменить метод main следующим образом.
public static void main(String[] args) {
MutEx mutEx = new MutEx(0, 2);
ClassX t1 = new ClassX(0, mutEx);
ClassY t2 = new ClassY(1, mutEx);
t1.start();
t2.start();
}
Запустите это, и вы получите тот же результат.
Это, вероятно, больше, чем необходимо для решения проблемы, но, поскольку это, кажется, введение в параллельное программирование, оно должно соответствовать тому, с чем вы столкнетесь.
Вероятно, у вас должен быть общий объект, о котором знают ваши потоки, чтобы они могли синхронизироваться через него. Вот так:
public class MyMutex {
private int whoGoes;
private int howMany;
public MyMutex(int first, int max) {
whoGoes = first;
howMany = max;
}
public synchronized int getWhoGoes() { return whoGoes; }
public synchronized void switchTurns() {
whoGoes = (whoGoes + 1) % howMany;
notifyAll();
}
public synchronized void waitForMyTurn(int id) throws
InterruptedException {
while (whoGoes != id) { wait(); }
}
}
Теперь ваши классы должны получить свой соответствующий идентификатор и этот общий объект.
public class ClassX implements Runnable {
private final int MY_ID;
private final MyMutex MUTEX;
public ClassX(int id, MyMutex mutex) {
MY_ID = id;
MUTEX = mutex;
}
public void methodAandB() {
for(int i = 0; i < 10; i++) {
try {
MUTEX.waitForMyTurn(MY_ID);
System.out.println("This is A and B ");
MUTEX.switchTurns();
} catch (InterruptedException ex) {
// Handle it...
}
}
}
@Override
public void run() { methodAandB(); }
}
ClassY
должен сделать то же самое. Дождитесь своей очереди, сделайте свое действие, а затем уступите очередь другой.
Если вам не нужно использовать Thread, попробуйте этот код:
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
methodAandB();
} else {
methodAorB();
}
}