Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 771 | blopes | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more |
||
| 3 | * contributor license agreements. See the NOTICE file distributed with |
||
| 4 | * this work for additional information regarding copyright ownership. |
||
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
||
| 6 | * (the "License"); you may not use this file except in compliance with |
||
| 7 | * the License. You may obtain a copy of the License at |
||
| 8 | * |
||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
| 10 | * |
||
| 11 | * Unless required by applicable law or agreed to in writing, software |
||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
| 14 | * See the License for the specific language governing permissions and |
||
| 15 | * limitations under the License. |
||
| 16 | */ |
||
| 17 | package async; |
||
| 18 | |||
| 19 | import java.text.DecimalFormat; |
||
| 20 | import java.util.List; |
||
| 21 | import java.util.Random; |
||
| 22 | import java.util.concurrent.CopyOnWriteArrayList; |
||
| 23 | import java.util.concurrent.atomic.AtomicInteger; |
||
| 24 | |||
| 25 | public class Stockticker implements Runnable { |
||
| 26 | public volatile boolean run = true; |
||
| 27 | protected final AtomicInteger counter = new AtomicInteger(0); |
||
| 28 | final List<TickListener> listeners = new CopyOnWriteArrayList<>(); |
||
| 29 | protected volatile Thread ticker = null; |
||
| 30 | protected volatile int ticknr = 0; |
||
| 31 | |||
| 32 | public synchronized void start() { |
||
| 33 | run = true; |
||
| 34 | ticker = new Thread(this); |
||
| 35 | ticker.setName("Ticker Thread"); |
||
| 36 | ticker.start(); |
||
| 37 | } |
||
| 38 | |||
| 39 | public synchronized void stop() { |
||
| 40 | // On context stop this can be called multiple times. |
||
| 41 | // NO-OP if the ticker thread is not set |
||
| 42 | // (i.e. stop() has already completed) |
||
| 43 | if (ticker == null) { |
||
| 44 | return; |
||
| 45 | } |
||
| 46 | run = false; |
||
| 47 | try { |
||
| 48 | ticker.join(); |
||
| 49 | }catch (InterruptedException x) { |
||
| 50 | Thread.interrupted(); |
||
| 51 | } |
||
| 52 | |||
| 53 | ticker = null; |
||
| 54 | } |
||
| 55 | |||
| 56 | public void shutdown() { |
||
| 57 | // Notify each listener of the shutdown. This enables them to |
||
| 58 | // trigger any necessary clean-up. |
||
| 59 | for (TickListener l : listeners) { |
||
| 60 | l.shutdown(); |
||
| 61 | } |
||
| 62 | // Wait for the thread to stop. This prevents warnings in the logs |
||
| 63 | // that the thread is still active when the context stops. |
||
| 64 | stop(); |
||
| 65 | } |
||
| 66 | |||
| 67 | public void addTickListener(TickListener listener) { |
||
| 68 | if (listeners.add(listener)) { |
||
| 69 | if (counter.incrementAndGet()==1) { |
||
| 70 | start(); |
||
| 71 | } |
||
| 72 | } |
||
| 73 | |||
| 74 | } |
||
| 75 | |||
| 76 | public void removeTickListener(TickListener listener) { |
||
| 77 | if (listeners.remove(listener)) { |
||
| 78 | if (counter.decrementAndGet()==0) { |
||
| 79 | stop(); |
||
| 80 | } |
||
| 81 | } |
||
| 82 | } |
||
| 83 | |||
| 84 | @Override |
||
| 85 | public void run() { |
||
| 86 | try { |
||
| 87 | |||
| 88 | Stock[] stocks = new Stock[] { new Stock("GOOG", 435.43), |
||
| 89 | new Stock("YHOO", 27.88), new Stock("ASF", 1015.55), }; |
||
| 90 | Random r = new Random(System.currentTimeMillis()); |
||
| 91 | while (run) { |
||
| 92 | for (int j = 0; j < 1; j++) { |
||
| 93 | int i = r.nextInt() % 3; |
||
| 94 | if (i < 0) { |
||
| 95 | i = i * (-1); |
||
| 96 | } |
||
| 97 | Stock stock = stocks[i]; |
||
| 98 | double change = r.nextDouble(); |
||
| 99 | boolean plus = r.nextBoolean(); |
||
| 100 | if (plus) { |
||
| 101 | stock.setValue(stock.getValue() + change); |
||
| 102 | } else { |
||
| 103 | stock.setValue(stock.getValue() - change); |
||
| 104 | } |
||
| 105 | stock.setCnt(++ticknr); |
||
| 106 | for (TickListener l : listeners) { |
||
| 107 | l.tick(stock); |
||
| 108 | } |
||
| 109 | |||
| 110 | } |
||
| 111 | Thread.sleep(850); |
||
| 112 | } |
||
| 113 | } catch (InterruptedException ix) { |
||
| 114 | // Ignore |
||
| 115 | } catch (Exception x) { |
||
| 116 | x.printStackTrace(); |
||
| 117 | } |
||
| 118 | } |
||
| 119 | |||
| 120 | |||
| 121 | public interface TickListener { |
||
| 122 | void tick(Stock stock); |
||
| 123 | void shutdown(); |
||
| 124 | } |
||
| 125 | |||
| 126 | public static final class Stock implements Cloneable { |
||
| 127 | protected static final DecimalFormat df = new DecimalFormat("0.00"); |
||
| 128 | protected final String symbol; |
||
| 129 | protected double value = 0.0d; |
||
| 130 | protected double lastchange = 0.0d; |
||
| 131 | protected int cnt = 0; |
||
| 132 | |||
| 133 | public Stock(String symbol, double initvalue) { |
||
| 134 | this.symbol = symbol; |
||
| 135 | this.value = initvalue; |
||
| 136 | } |
||
| 137 | |||
| 138 | public void setCnt(int c) { |
||
| 139 | this.cnt = c; |
||
| 140 | } |
||
| 141 | |||
| 142 | public int getCnt() { |
||
| 143 | return cnt; |
||
| 144 | } |
||
| 145 | |||
| 146 | public String getSymbol() { |
||
| 147 | return symbol; |
||
| 148 | } |
||
| 149 | |||
| 150 | public double getValue() { |
||
| 151 | return value; |
||
| 152 | } |
||
| 153 | |||
| 154 | public void setValue(double value) { |
||
| 155 | double old = this.value; |
||
| 156 | this.value = value; |
||
| 157 | this.lastchange = value - old; |
||
| 158 | } |
||
| 159 | |||
| 160 | public String getValueAsString() { |
||
| 161 | return df.format(value); |
||
| 162 | } |
||
| 163 | |||
| 164 | public double getLastChange() { |
||
| 165 | return this.lastchange; |
||
| 166 | } |
||
| 167 | |||
| 168 | public void setLastChange(double lastchange) { |
||
| 169 | this.lastchange = lastchange; |
||
| 170 | } |
||
| 171 | |||
| 172 | public String getLastChangeAsString() { |
||
| 173 | return df.format(lastchange); |
||
| 174 | } |
||
| 175 | |||
| 176 | @Override |
||
| 177 | public int hashCode() { |
||
| 178 | return symbol.hashCode(); |
||
| 179 | } |
||
| 180 | |||
| 181 | @Override |
||
| 182 | public boolean equals(Object other) { |
||
| 183 | if (other instanceof Stock) { |
||
| 184 | return this.symbol.equals(((Stock) other).symbol); |
||
| 185 | } |
||
| 186 | |||
| 187 | return false; |
||
| 188 | } |
||
| 189 | |||
| 190 | @Override |
||
| 191 | public String toString() { |
||
| 192 | StringBuilder buf = new StringBuilder("STOCK#"); |
||
| 193 | buf.append(getSymbol()); |
||
| 194 | buf.append('#'); |
||
| 195 | buf.append(getValueAsString()); |
||
| 196 | buf.append('#'); |
||
| 197 | buf.append(getLastChangeAsString()); |
||
| 198 | buf.append('#'); |
||
| 199 | buf.append(String.valueOf(getCnt())); |
||
| 200 | return buf.toString(); |
||
| 201 | |||
| 202 | } |
||
| 203 | |||
| 204 | @Override |
||
| 205 | public Object clone() { |
||
| 206 | Stock s = new Stock(this.getSymbol(), this.getValue()); |
||
| 207 | s.setLastChange(this.getLastChange()); |
||
| 208 | s.setCnt(this.cnt); |
||
| 209 | return s; |
||
| 210 | } |
||
| 211 | } |
||
| 212 | } |