[英]How do I run 2 Threads alternately
我是线程的新手,我正在尝试使 Output 看起来像:aAbBcCdDeE...。 我搜索并尝试了很多东西,但没有任何东西真正起作用。 在练习中,您应该使用全局变量 boolean 来完成它,但我并没有真正找到任何有用的东西并且有点迷路。 感谢您的帮助!
public class ABCThread implements Runnable {
char c;
public ABCThread(char c) {
this.c = c;
}
@Override
public synchronized void run() {
for (char i = 0; i < 26; i++) {
System.out.println(c++);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ABCThread('a'));
Thread t2 = new Thread(new ABCThread('A'));
t1.start();
t2.start();
}
}
Output:
a
A
B
b
C
c
d
D
e
E
f
F
G
g
H
h
I
i
J
j
快速回答:
您不能强制线程在特定时刻运行。 不过,您可以做的是让这两个运行“不同步”(与异步编码无关)。
Thread t1 = new Thread(new ABCThread('a'));
Thread.sleep(250);
Thread t2 = new Thread(new ABCThread('A'));
第一个线程大约每 500 毫秒打印一次,第二个线程将在 250、750、1250 等时打印一次。请注意,这不是在实际程序中解决此问题的正确方法。 但话又说回来,您也可能不会将Thread.sleep(500)
添加到 run 方法中。
更好的:
您需要线程之间的同步。 因为你启动了两个线程,所以你可以使用 boolean。
public class ABCThread implements Runnable {
char c;
static boolean synchronizer = false;
boolean runOn;
public ABCThread(char c, boolean runOn) {
this.c = c;
this.runOn = runOn;
}
@Override
public synchronized void run() {
int count = 0;
while(count < 26)
{
if(runOn != synchronizer)
{
Thread.sleep(100);
continue;
}
count++;
synchronizer = !synchronizer;
System.out.println(c++);
}
}
Thread t1 = new Thread(new ABCThread('a', false));
Thread t2 = new Thread(new ABCThread('A', true));
只需输入此内容。 它可能无法编译。 Thread.sleep(100)
只是一些数字。 它可能会更低,但对于这个问题来说并不重要。
更好的是前面的代码可以只用 2 个线程运行。 1 将停留在 synchronizer = false 状态。 如果添加第三个同步器将无法工作,因为它只有 2 个状态。 您可以添加一个 integer 而不是 boolean 和另一个 integer amountOfThreads。 需要将 amountOfThreads 设置为您将启动的线程数量,然后在线程打印时增加原子 integer 并且如果同步器(原子 int)大于 amountOfThreads。 将其设置为 0。
您应该使用boolean
来控制哪个线程打印:
这样,线程将交替。 此外,如果您在线程之间使用信号而不是sleep
,所有这些都会快得多:
import java.util.*;
import java.lang.*;
import java.io.*;
public class ABCThread implements Runnable {
static Object monitor = new Object();
static boolean turn = false;
char c;
final boolean myTurn;
public ABCThread(char c, boolean myTurn) {
this.c = c;
this.myTurn = myTurn;
}
@Override
public void run() {
for (char i = 0; i < 26; i++) {
synchronized(monitor) {
while (turn != myTurn) {
try {
// Note that the lock is release while I'm waiting,
// So the other thread can claim it here.
monitor.wait();
} catch (Exception e) {
}
}
System.out.println(c++);
turn = !myTurn;
monitor.notifyAll();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ABCThread('a', false));
Thread t2 = new Thread(new ABCThread('A', true));
t1.start();
t2.start();
t1.join();
t2.join();
}
}
下面是演示如何实现该目标的代码。
public class Main
{
// The shared resource
public static class State {
private int val;
private int nStates;
// Init value and number of states.
public State(int init, int nStates) {
this.val = init;
this.nStates = nStates;
}
int get() {
return val;
}
// Define how to get to next state. For simple use case, just increase then modulo it. eg: 0, 1, 0, 1
// Avoid modulo in-case you need very very high performance.
void next() {
this.val = (this.val + 1) % nStates;
}
}
public static class ABCThread implements Runnable{
private char c;
private State s;
private int type;
public ABCThread(char c, State s, int type) {
this.c = c;
this.s = s;
this.type = type;
}
@Override
public void run() {
try {
for (char i = 0; i < 26; i++) {
// Do things synchronously
synchronized(s){
while(s.get() != type) {
// Wait for our turn.
s.wait();
}
System.out.print(c++);
// Update state
s.next();
// Notify to other threads to do their job.
s.notifyAll();
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// Define the state.
State s = new State(0, 2);
/* Uncomment this block to have 3 synchronous threads. Will print aA1bB2...
s = new State(0, 3);
Thread t3 = new Thread(new ABCThread('1', s, 2));
t3.start();
t3.join();
*/
Thread t1 = new Thread(new ABCThread('a', s, 0));
Thread t2 = new Thread(new ABCThread('A', s, 1));
// Start threads
t1.start();
t2.start();
// Wait for these threads to finish before exit.
t1.join();
t2.join();
}
}
这是解决给定问题的解决方案之一。 它使用wait
等待当前线程打印完一个字母后notify
另一个线程打印它的字母,如此循环重复。 线程wait
和notify
的概念在这里得到了很好的解释。
简短的介绍:
要wait
或notify
任何线程,它(调用线程)必须获取任何公共 object 上的锁。在下面的示例中,每个线程正在获取this
(自身)(通过同步run
方法)的锁以wait
并通知opponent
(另一个线程)。
public class App implements Runnable {
char c;
App opponent;
boolean go;
public App(char c, boolean go) {
this.c = c;
this.go = go;
}
public void setOpponent(App opponent) {
this.opponent = opponent;
}
public static void main(String[] args) {
App a = new App('a', true);
App b = new App('A', false);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
a.setOpponent(b);
b.setOpponent(a);
t1.start();
t2.start();
}
@Override
public synchronized void run() {
for (char i = 0; i < 26; i++) {
try {
if (go) {
System.out.println(c++);
this.wait();
synchronized (opponent) {
opponent.notify();
}
} else {
System.out.println(c++);
synchronized (opponent) {
opponent.notify();
}
this.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
这是上述代码的更简化和易于理解的版本。 在这段代码中,两个线程都在获取同一个lock
object 上的锁,打印这封信,进入WAIT
state(因此释放锁)并转向其他BLOCKED
线程等待 lock 上的lock
。 然后另一个线程在 lock 上获取lock
,打印字母,通知等待lock
object 的前一个线程,并进入WAIT
状态,从而释放锁。
public class App2 implements Runnable {
char c;
Object lock;
boolean go;
public App2(char c, boolean go) {
this.c = c;
this.go = go;
}
public void setLock(Object lock) {
this.lock = lock;
}
public static void main(String[] args) {
App2 a = new App2('a', true);
App2 b = new App2('A', false);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
Object lock = new Object();
a.setLock(lock);
b.setLock(lock);
t1.start();
t2.start();
}
@Override
public void run() {
for (char i = 0; i < 26; i++) {
synchronized (lock) {
try {
if (go) {
System.out.println(c++);
lock.wait();
lock.notify();
} else {
System.out.println(c++);
lock.notify();
lock.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
更新:
以上两种方式在大多数情况下都有效,但并不能保证每次t1
都先于t2
执行。 虽然t1
在t2
之前启动,但这并不意味着线程调度器总是选择t1
在t2
之前执行。 为确保在任何情况下t1
都将在t2
之前执行,我们需要确保t2
在t1
处于RUNNABLE
state(即运行)状态时启动。 以下是我们如何实现它的方法之一:
public class App3 implements Runnable {
char c;
App3 opponent;
boolean go;
boolean createOpponent = false;
public App3(char c, boolean go) {
this.c = c;
this.go = go;
}
public void setOpponent(App3 opponent) {
this.opponent = opponent;
}
public void setCreateOpponent(boolean createOpponent) {
this.createOpponent = createOpponent;
}
public static void main(String[] args) {
App3 a = new App3('a', true);
App3 b = new App3('A', false);
Thread t1 = new Thread(a);
a.setOpponent(b);
a.setCreateOpponent(true);
b.setOpponent(a);
t1.start();
}
@Override
public synchronized void run() {
if (createOpponent) {
setCreateOpponent(false);
new Thread(opponent).start();
}
for (char i = 0; i < 26; i++) {
try {
if (go) {
System.out.println(c++);
this.wait();
synchronized (opponent) {
opponent.notify();
}
} else {
System.out.println(c++);
synchronized (opponent) {
opponent.notify();
}
this.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
希望这可以帮助...
public class ABCThread implements Runnable {
char c;
boolean flag;
public ABCThread(char c, boolean flag) {
this.c = c;
this.flag = flag;
}
@Override
public synchronized void run() {
for (char i = 0; i < 52; i++) {
try {
if (flag) {
System.out.println(c++);
notifyAll();
flag = false;
wait(100);
} else {
flag = true;
wait(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ABCThread('a', true));
Thread t2 = new Thread(new ABCThread('A', false));
t1.start();
t2.start();
}
}
或者您可以定义单独的方法来打印小写字母和大写字母,并在两个单独的线程中运行它们
public class ABCThread {
boolean flag;
public ABCThread(boolean flag) {
this.flag = flag;
}
public static void main(String[] args) throws InterruptedException {
ABCThread abc = new ABCThread(false);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
abc.printSmallLetters();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
abc.printCapitalLetters();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
synchronized void printSmallLetters() throws InterruptedException {
for (char i = 'a'; i < 'z'; i++) {
while (flag == true) {
wait();
}
System.out.println(i);
notifyAll();
flag = true;
}
}
synchronized void printCapitalLetters() throws InterruptedException {
for (char i = 'A'; i < 'Z'; i++) {
while (flag == false) {
wait();
}
System.out.println(i);
notifyAll();
flag = false;
}
}
}
只需将 println 替换为 print 即可获得像这样的系列 output 除了一切似乎都很好,您可以看到我在上面的屏幕截图中得到的 output
决不。 线程的执行顺序无法控制。可以使用Thread.yield()。 但是 yield() - 试图告诉调度程序执行下一个线程,但它停留在 RUNNABLE state。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.