找到你要的答案

Q:Synchronizing Threads in Java using monitor class

Q:使用Monitor类java线程同步

The following program creates threads that generate random numbers.

How do I change the Monitor class so it will control the threads in a way that the print outs will be printed by the order of each Thread's ID?

Solutions like "invoke run method instead of start" are not accepted.

The given classed are:

public class Main {
    public static void main(String[] args) {
        Monitor mon = new Monitor();
        for (int i = 0; i < 20; i++)
            new T(i, mon).start();

        System.out.println("Finished");
    }
}

public class Monitor {

    public void print(int id, int num) {
        System.out.println("id=" + id + " num=" + num);
    }
}

public class T extends Thread {
    private int id;
    private Monitor mon;

    public T(int i, Monitor m) {
        id = i;
        mon = m;
    }

    private int calc() {
        int num = 0;
        for (int i = 0; i < 10; i++)
            num = num + (int) (Math.random() * 10);
        return num;
    }

    public void run() {
        int num = calc();
        mon.print(id, num);
    }
}

下面的程序创建生成随机数的线程。

我如何更改监视器类,以便它将控制线程的方式打印打印将由每个线程的ID的顺序打印?

不接受“调用运行方法而不是启动”之类的解决方案。

给定的分类是:

public class Main {
    public static void main(String[] args) {
        Monitor mon = new Monitor();
        for (int i = 0; i < 20; i++)
            new T(i, mon).start();

        System.out.println("Finished");
    }
}

public class Monitor {

    public void print(int id, int num) {
        System.out.println("id=" + id + " num=" + num);
    }
}

public class T extends Thread {
    private int id;
    private Monitor mon;

    public T(int i, Monitor m) {
        id = i;
        mon = m;
    }

    private int calc() {
        int num = 0;
        for (int i = 0; i < 10; i++)
            num = num + (int) (Math.random() * 10);
        return num;
    }

    public void run() {
        int num = calc();
        mon.print(id, num);
    }
}
answer1: 回答1:

You just need the thread trying to print to wait and block until its ID is the expected ID:

public class Monitor {

    private final Object lock = new Object();
    private int expectedId = 0;

    public void print(int id, int num) {
        synchronized (lock) {
            while (id != expectedId) {
                try {
                    lock.wait();
                }
                catch (InterruptedException e) {
                    return;
                }
            }
            System.out.println("id=" + id + " num=" + num);
            expectedId++;
            lock.notifyAll();
        }
    }
}

你只需要线程试图打印等待和阻止,直到它的ID是预期的ID:

public class Monitor {

    private final Object lock = new Object();
    private int expectedId = 0;

    public void print(int id, int num) {
        synchronized (lock) {
            while (id != expectedId) {
                try {
                    lock.wait();
                }
                catch (InterruptedException e) {
                    return;
                }
            }
            System.out.println("id=" + id + " num=" + num);
            expectedId++;
            lock.notifyAll();
        }
    }
}
answer2: 回答2:

For the strange task only strange solution can be proposed. My version would be like this:

import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

public class Monitor {
    Map<Integer, Integer> map = new TreeMap<>();

    public synchronized void print(int id, int num) {
        map.put(id, num);
        if(map.size() == 20) {
            for(Entry<Integer, Integer> entry : map.entrySet())
            System.out.println("id=" + entry.getKey() + " num=" + entry.getValue());
        }
    }
}

It solves your problem. Objections like "it depends on number of threads" are not accepted.

对于奇怪的任务只能提出奇怪的解决方案。我的版本将是这样:

import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

public class Monitor {
    Map<Integer, Integer> map = new TreeMap<>();

    public synchronized void print(int id, int num) {
        map.put(id, num);
        if(map.size() == 20) {
            for(Entry<Integer, Integer> entry : map.entrySet())
            System.out.println("id=" + entry.getKey() + " num=" + entry.getValue());
        }
    }
}

它解决了你的问题。像“它依赖于线程数”的异议不被接受。

answer3: 回答3:

Inspired by @JBNizet's answer I came to this solution (using this as lock):

public class Monitor {
    private int currId = 0;

    public synchronized void print(int id, int num) {
        while (id != currId) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("id=" + id + " num=" + num);
        currId++;
        notifyAll();
    }
}

灵感来自@ jbnizet回答我来到这个解决方案(使用这个锁):

public class Monitor {
    private int currId = 0;

    public synchronized void print(int id, int num) {
        while (id != currId) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("id=" + id + " num=" + num);
        currId++;
        notifyAll();
    }
}
java  multithreading