3

假设一个线程打印“Hello”,另一个打印“World”。我曾经成功做过一次,如下:包线程;

public class InterThread {

    public static void main(String[] args) {
        MyThread mt=new MyThread();
        mt.start();
        synchronized(mt){
            System.out.println("Hello");
            try {
                mt.wait();
                i++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}

class MyThread extends Thread{

    public void run(){
        synchronized(this){
        System.out.println("World!");
        notify();
        }
    }
}

如何进行多次打印,比如 5 次?我尝试在同步块周围放置 for 循环,但没有用。

4

7 回答 7

7

这里是两个相互依赖的线程,我们需要两个同步对象。它们可能是许多事情之一。一个整数,另一个对象;一个布尔值另一个对象;两个对象;信号量等等。同步技术可以是 Monitor 或 Semaphore 任何你喜欢的方式,但它们必须是两个。

我已修改您的代码以使用信号量而不是监视器。信号量的工作更加透明。您可以看到正在发生的获取和释放。监视器是更高的结构。因此 Synchronized 在幕后工作。

如果您对以下代码感到满意,则可以将其转换为使用 Monitors。

    import java.util.concurrent.Semaphore;

    public class MainClass {

        static Semaphore hello = new Semaphore(1);
        static Semaphore world = new Semaphore(0);

        public static void main(String[] args) throws InterruptedException {
            MyThread mt=new MyThread();     
            mt.hello = hello;
            mt.world = world;
            mt.start();

            for (int i=0; i<5; i++) {
                hello.acquire(); //wait for it
                System.out.println("Hello");

                world.release(); //go say world
            }
        }
    }

    class MyThread extends Thread{

        Semaphore hello, world;

        public void run(){
            try {
                for(int i = 0; i<5; i++) {
                    world.acquire(); // wait-for it
                    System.out.println("  World!");

                    hello.release(); // go say hello
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
于 2013-06-06T13:58:47.620 回答
3

这里的目标是同步线程,以便在一个完成时通知另一个。如果我必须做到,那将是 2 个线程使用不同的数据执行相同的代码。每个线程都有自己的数据("Hello"true到 T1"World"false到 t2),并共享一个变量turn和一个单独的锁对象。

while(/* I need to play*/){
  synchronized(lock){
    if(turn == myturn){
      System.out.println(mymessage);
      turn = !turn; //switch turns
      lock.signal();
     }
     else{
       lock.wait();
     }
  }
}
于 2013-06-06T13:43:36.140 回答
3

在你开始尝试让它工作五次之前,你需要确保它工作一次!

您的代码不能保证总是打印 Hello World!- 在获取 mt 的锁之前可能会中断主线程(请注意,锁定线程对象通常不是一个好主意)。

MyThread mt=new MyThread();
mt.start();
\\ interrupted here
synchronized(mt){
  ...

一种可以推广到多次这样做的方法是使用原子布尔值

import java.util.concurrent.atomic.AtomicBoolean;
public class InterThread {

    public static void main(String[] args) {
        int sayThisManyTimes = 5;
        AtomicBoolean saidHello = new AtomicBoolean(false);

        MyThread mt=new MyThread(sayThisManyTimes,saidHello);
        mt.start();

        for(int i=0;i<sayThisManyTimes;i++){
          while(saidHello.get()){} // spin doing nothing!
          System.out.println("Hello ");
          saidHello.set(true);
        }    
    }

}

class MyThread extends Thread{

    private final int sayThisManyTimes;
    private final AtomicBoolean saidHello;
    public MyThread(int say, AtomicBoolean said){
      super("MyThread");
      sayThisManyTimes = say;
      saidHello = said;
    }

    public void run(){
        for(int i=0;i<sayThisManyTimes;i++){
          while(!saidHello.get()){} // spin doing nothing!
          System.out.println("World!");
          saidHello.set(false);
        }
    }
}
于 2013-06-06T13:58:21.460 回答
3
public class ThreadSeq {

    Object hello = new Object();
    Object world = new Object();


    public static void main(String[] args) throws InterruptedException {
        for(int i=0; i<6;i++){
            Runnable helloTask = new Runnable(){
                @Override
                public void run(){
                    new ThreadSeq().printHello();
                }
            };

            Runnable worldTask = new Runnable(){
                @Override
                public void run(){
                    new ThreadSeq().printWorld();
                }
            };

            Thread t1 = new Thread(helloTask);
            Thread t2 = new Thread(worldTask);
            t1.start();
            t1.join();
            t2.start();
            t2.join();
        }

    }

    public void printHello(){
        synchronized (hello) {
            System.out.println("Hello");
        }
    }

    public void printWorld(){
        synchronized (world) {
            System.out.println("World");
        }
    }
}
于 2014-12-25T20:04:45.190 回答
1

这是在 C 中:

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t hello_lock, world_lock;

void printhello()
{
    while(1) {
        pthread_mutex_lock(&hello_lock);
        printf("Hello ");
        pthread_mutex_unlock(&world_lock);
    }
}


void printworld()
{
    while(1) {
        pthread_mutex_lock(&world_lock);
        printf("World ");
        pthread_mutex_unlock(&hello_lock);
    }
}

int main()  
{
    pthread_t helloThread, worldThread;

    pthread_create(&helloThread,NULL,(void *)printhello,NULL);
    pthread_create(&helloThread,NULL,(void *)printhello,NULL);

    pthread_join(helloThread);
    pthread_join(worldThread);

    return 0;
}
于 2014-02-12T10:34:22.633 回答
0

有两个线程,并且都有自己的数据(“Hello”和 true 对 ht,“World”和 false 对 wt),并且共享一个变量 objturn。

public class HelloWorldBy2Thread {  
    public static void main(String[] args) {
        PrintHelloWorld hw = new PrintHelloWorld(); 
        HelloThread ht = new HelloThread(hw);
        WorldThread wt = new WorldThread(hw);
        ht.start();
        wt.start();
    }
}
public class HelloThread extends Thread {   
    private PrintHelloWorld phw;
    private String hello;
    public HelloThread(PrintHelloWorld hw) {
        phw = hw;
        hello = "Hello";
    }   
    @Override
    public void run(){
        for(int i=0;i<10;i++)
            phw.print(hello,true);
    }
}
public class WorldThread extends Thread {
    private PrintHelloWorld phw;
    private String world;
    public WorldThread(PrintHelloWorld hw) {
        phw = hw;
        world = "World";
    }
    @Override
    public void run(){
        for(int i=0;i<10;i++)
            phw.print(world,false);
    }
}
public class PrintHelloWorld {  
    private boolean objturn=true;
    public synchronized void print(String str, boolean thturn){
        while(objturn != thturn){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print(str+" ");
        objturn = ! thturn;
        notify();               
    }
}
于 2016-07-25T16:52:33.613 回答
0

以简单的方式,我们可以使用wait()并且notify()不创建任何额外的对象来做到这一点。

public class MainHelloWorldThread {

    public static void main(String[] args) {

        HelloWorld helloWorld = new HelloWorld();

            Thread t1 = new Thread(() -> {
                try {
                    helloWorld.printHello();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

            Thread t2 = new Thread(() -> {
                try {
                    helloWorld.printWorld();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

        // printHello() will be called first
        t1.setPriority(Thread.MAX_PRIORITY);

        t1.start();
        t2.start();

    }
}

class HelloWorld {

    public void printHello() throws InterruptedException {

        synchronized (this) {
            // Infinite loop
            while (true) {
                // Sleep for 500ms
                Thread.sleep(500);
                System.out.print("Hello ");

                wait();
                // This thread will wait to call notify() from printWorld()

                notify();
                // This notify() will release lock on printWorld() thread
            }
        }
    }   

    public void printWorld() throws InterruptedException {

        synchronized (this) {
            // Infinite loop
            while (true) {
                // Sleep for 100ms
                Thread.sleep(100); 
                System.out.println("World");

                notify();
                // This notify() will release lock on printHello() thread

                wait();
                // This thread will wait to call notify() from printHello()
            }
        }
    }
}
于 2019-02-11T12:44:08.233 回答