Сегодняшний пример - два потока перебрасывающиеся объектом.
----------
Следственный эксперимент: класс PingPong запускает два класса Player, а они перебрасываются классом Item. Item содержит простой счетчик типа int, считающий количество передач. Передачи осуществляются через механизм wait()/notify().
На тестовом компьютере (AMD Duron 1300, WinXP, jdk 1.6_13) 100.000.000 передач было выполнено за 232с, т.е. на одно переключение контекста уходило в среднем 232 * 10 * 1.3 = 3016 тактов. В примере я сократил 100.000.000 до 1.000.000.
-------------------------- start PingPong.java file
import java.util.concurrent.CountDownLatch;
public class PingPong {
// constant
public static final int ITERATION_COUNT = 1000 * 1000;
// global variables :(
public static final Item item = new Item();
public static final CountDownLatch start = new CountDownLatch(1);
public static final CountDownLatch stop = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
// init section
new Thread(new Player(false)).start(); //player #0
new Thread(new Player(true)).start(); //player #1
// work section
long startTime = System.nanoTime();
start.countDown();
stop.await();
long deltaTime = System.nanoTime() - startTime;
// info-to-console section
System.out.println("" + ITERATION_COUNT + " transfers take " + deltaTime + " nanosecs");
}
}
class Item {
int counter = 0;
}
class Player implements Runnable {
private final boolean imOdd;
public Player(boolean imOdd) {
this.imOdd = imOdd;
}
public void run() {
// await for start ping-ponging
try {
PingPong.start.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (PingPong.item) {
while (true) {
// wait for my turn (avoid spirious wakeup)
while (((PingPong.item.counter & 1) == 1) == imOdd) {
try {
PingPong.item.wait(); // wait for "Ping"
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// increment Ping-Poin counter
PingPong.item.counter++;
// do "Pong"
PingPong.item.notify();
if (PingPong.item.counter >= PingPong.ITERATION_COUNT) {
PingPong.stop.countDown(); // show for PingPoint.class that my work doing
return; // break, thats all
}
}
}
}
}
-------------------------- end PingPong.java file
Замечания:
- пуск и ожидание останова двух потоков делается с использованием java.util.concurrent.CountDownLatch. Это одна из "законных" функций этого класса.
- я довольно небрежно работаю с InterruptedException так как цель - просто демонстрация
- в классе PingPong три глобальных переменных, это плохо, но для демонстрации - сгодится
- в данном примере всего два игрока и так легко его не приспособишь для большего количества (так как в Player.java поле типа boolean имеет всего два значения (четный - нечетный))
------------------
Задачка - 1: сделать 100 потоков перебрасывающихся по кругу одним Item.
Задачка - 2: сделать 100 потоков перебрасывающихся по кругу одновременно 10 Item.
Комментариев нет:
Отправить комментарий