我正在学习信号量和多线程的一般用法,但我有点被卡住了。我有两个线程分别打印G和H,我的目标是交替每个线程的输出,使输出字符串如下所示;
G
H
G
H
G
H这两个类中的每个类都有一个类似于下面的布局
public class ClassA extends Thread implements Runnable{
Semaphore semaphore = null;
public ClassA(Semaphore semaphore){
this.semaphore = semaphore;
}
public void run() {
while(true)
{
try{
semaphore.acquire();
for(int i=0; i<1000; i++){
System.out.println("F");
}
Thread.currentThread();
Thread.sleep(100);
}catch(Exception e)
{
System.out.println(e.toString());
}
semaphore.release();
}
}
}下面是我的主类
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(1);
ClassA clasA = new ClassA(semaphore);
Thread t1 = new Thread(clasA);
ClassB clasB = new ClassB(semaphore);
Thread t2 = new Thread(clasB);
t1.start();
t2.join();
t2.start();我得到的输出与我预期的结果相差太远。有谁能帮帮我吗?我是不是误用了信号灯?有什么帮助吗?
发布于 2017-05-08 03:07:18
信号量不能帮助您解决这样的任务。
据我所知,JVM在线程执行中不承诺任何顺序。这意味着如果您运行多个线程,一个线程可以连续执行几次,并且拥有比其他线程更多的处理器时间。因此,如果你想让你的线程以特定的顺序执行,你可以,对于最简单的例子,创建一个静态的布尔变量,它将扮演你的线程的切换器的角色。使用wait()和notify()方法将是更好的方法,我认为Interface Condition将是最好的方法。
import java.io.IOException;
public class Solution {
public static boolean order;
public static void main(String[] args) throws IOException, InterruptedException {
Thread t1 = new ThreadPrint("G", true);
Thread t2 = new ThreadPrint("O", false);
t1.start();
t2.start();
t2.join();
System.out.println("Finish");
}
}
class ThreadPrint extends Thread {
private String line;
private boolean order;
public ThreadPrint(String line, boolean order) {
this.line = line;
this.order = order;
}
@Override
public void run() {
int z = 0;
while (true) {
try {
for (int i = 0; i < 10; i++) {
if (order == Solution.order) {
System.out.print(line + " ");
Solution.order = !order;
}
}
sleep(100);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
}顺便说一句,可能还有另一个问题,因为System.out通常是一个操作系统缓冲区,你的操作系统可以按自己的顺序输出你的消息。
附注:你不应该同时继承Thread和实现Runnable
public class ClassA extends Thread implements Runnable{因为Thread类已经实现了Runnable。你只能选择一种更适合你的方式。
你应该启动一个线程,然后加入它,反之亦然。
t1.start();
t2.join();
t2.start();发布于 2017-05-08 07:02:18
正如其他人指出的那样,锁本身并不强制执行任何顺序,最重要的是,您不能确定线程何时启动(调用Thread.start()将在将来的某个时候启动线程,但这可能需要一段时间)。
但是,您可以使用锁(如Semaphore)来强制执行命令。在这种情况下,您可以使用两个信号量来打开和关闭线程(交替)。这两个线程(或Runnables)确实需要提前知道对方--一种更动态的方法,线程可以“加入”到参与方,这将更加复杂。
下面是一个具有可重复结果的可运行示例类(在测试多线程时,拥有这样的类总是一件好事)。我将留给您去弄清楚它为什么以及如何工作。
import java.util.concurrent.*;
public class AlternateSem implements Runnable {
static final CountDownLatch DONE_LATCH = new CountDownLatch(2);
static final int TIMEOUT_MS = 1000;
static final int MAX_LOOPS = 10;
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
try {
AlternateSem as1 = new AlternateSem(false);
AlternateSem as2 = new AlternateSem(true);
as1.setAlternate(as2);
as2.setAlternate(as1);
executor.execute(as1);
executor.execute(as2);
if (DONE_LATCH.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
System.out.println();
System.out.println("Done");
} else {
System.out.println("Timeout");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdownNow();
}
}
final Semaphore sem = new Semaphore(0);
final boolean odd;
AlternateSem other;
public AlternateSem(boolean odd) {
this.odd = odd;
}
void setAlternate(AlternateSem other) { this.other = other; }
void release() { sem.release(); }
void acquire() throws Exception { sem.acquire(); }
@Override
public void run() {
if (odd) {
other.release();
}
int i = 0;
try {
while (i < MAX_LOOPS) {
i++;
other.acquire();
System.out.print(odd ? "G " : "H ");
release();
}
} catch (Exception e) {
e.printStackTrace();
}
DONE_LATCH.countDown();
}
}https://stackoverflow.com/questions/43834700
复制相似问题