简体   繁体   中英

Multiple Threads For a Java Timer

I am trying to write a short Java program that uses multiple threads to create a timer. When the timer hits 7 or 15 seconds, it will print a message.

I need to create a shared counter. A time-printing thread increments the counter by one and prints its value each second from the start of execution. A message-printing thread prints a message every fifteen seconds and another message-printing thread that prints a different message every seven seconds. These two threads need to be done without modifying the time-printing thread.

All these threads need to share the counter object that updates every second. The time-printing thread will notify other threads to read the counter object each time it updates. Then, each message-printing thread will read the counter value and see if its assigned time period has occured.

The output should look like this:

1 2 3 4 5 6
7 second message
7 8 9 10 11 12 13
7 second message
14
15 second message
15 16 17 18 19 20
7 second message
21 22 23 24  . . .

I need to do this by creating a thread for the timer, a thread for the 7 second message, and a thread for the 15 second message. I've built this below:

import java.lang.Class;
import java.lang.Object;

class T1 extends Thread {
    private Main2 s;
    private int t;
    T1 (Main2 s) { this.s = s; }
    public void run()
    {
        while(true) {
            try { Thread.sleep(1000); }
            catch (InterruptedException e) { e.printStackTrace(); }
            s.setSharedTime (++t);
            System.out.print(t + " ");
        }
    }
}

class T2 extends Thread {
    private Main2 s;
    T2 (Main2 s) { this.s = s; }
    public void run()
    {
        while(true) { 
            int t = s.getSharedTime ();
            System.out.println();
            System.out.println ("7 second message");
        }
    }
}

class T3 extends Thread {
    private Main2 s;
    T3 (Main2 s) { this.s = s; }
    public void run()
    {
        while(true) { 
            int t = s.getSharedTime ();
            System.out.println();
            System.out.println ("15 second message");
        }
    }
}

public class Main2 {
    private int time;
    private boolean share = true;

    public static void main(String[] args) {
        Main2 s = new Main2();
        new T1 (s).start();
        new T2 (s).start();
        new T3 (s).start();
    }

    synchronized void setSharedTime (int s) {
        while (!share) {
            try { wait (); }
            catch (InterruptedException e) {}
        }
        this.time = s;
        if(s % 7 == 0)
            share = false;
        if(s % 15 == 0)
            share = false;
        notify ();
    }

    synchronized int getSharedTime () {
        while (share) {
            try { wait (); }
            catch (InterruptedException e) { }
        }
        share = true;
        notify ();
        return time;
    }
}

The problem I'm having with this is I cannot throw the 7 second and 15 second messages at the right times. How do I run these three threads together to put together a working timer?

In your code, you use classes T2 and T3 to print the 7 and 15 second messages, but there is no identification of which is which and they are effectively identical, save the name and the String that is printed. When notify() is called there is no specifiable order in which the lock is given. From the Javadocs for notify():

The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object

So whichever method (run() of T2 or run() of T3) that gets the lock on getSharedTime() will continue and print. Look at this question and the Javadocs for more information on that.

This is a similar way to do the same thing, I moved the checking if the time is a multiple of 7 or 15 to their respective classes, and structured the wait()'s and notify()'s differently. I also synchronized the printing with the Timer class so that all of the wait()'s are notified (effectively) at the same time. Printing the time at each second is handled in the Timer class, and the way that it is setup now will give the output that you specified, but switching the printing and call of setTime and initializing time to 0 will give an output that is more accurate to the current time.

class Timer extends Thread{
    private int time = 1;
    private boolean setting = false;

    public void run(){
        while(true){
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.print(time + " ");
            setTime(time + 1);
            //Switching the order of these 2 ^^^ statements and initializing time to 0 will give an output that is more accurate to the time.
        }
    }
    public synchronized int getTime(){
        while(setting){
            try {
                wait(); //This will only be run on the off-chance that setTime is being run at the same time.
            } catch (InterruptedException e) {  }
        }

        return time;
    }
    public synchronized void setTime(int t){
        setting = true;
        this.time = t;
        setting = false;
        notifyAll();
    }
}

class Timer7 extends Thread{
    Timer timer;
    public Timer7(Timer t){
        this.timer = t;
    }

    public void run(){
        synchronized(timer){
            while(true){

                try {
                    timer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if(timer.getTime() % 7 == 0){
                    System.out.print("\n7 Second Message\n");
                }

            }
        }
    }
}

class Timer15 extends Thread{
    Timer timer;
    public Timer15(Timer t){
        this.timer = t;
    }

    public void run(){
        synchronized(timer){
            while(true){

                try {
                    timer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if(timer.getTime() % 15 == 0){
                    System.out.print("\n15 Second Message\n");
                }

            }
        }
    }
}

public class Main2 {

    public static synchronized void main(String[] args) {

        Timer timer = new Timer();
        timer.start();

        Timer7 t7 = new Timer7(timer);
        t7.start();

        Timer15 t15 = new Timer15(timer);
        t15.start();

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM