public void write(int b) throws IOException {
     super.write(b);
     writer.write((byte)b);
 }
--------------------------------------------------------------------------------------------------------------------------------------
public void write(int b) throws IOException {
     crc = crc * 33 + b;
 }
--------------------------------------------------------------------------------------------------------------------------------------
private FileOutputStream writer;
--------------------------------------------------------------------------------------------------------------------------------------
writer = new FileOutputStream(currentFileName);
--------------------------------------------------------------------------------------------------------------------------------------
private String currentFileName;
--------------------------------------------------------------------------------------------------------------------------------------
// Zamiana FileOutputStream writer na BufferedOutputStream
// private FileOutputStream writer;
 private BufferedOutputStream writer;
--------------------------------------------------------------------------------------------------------------------------------------
// Inicjacja BufferedOutputStream
// writer = new FileOutputStream(currentFileName);
writer = new BufferedOutputStream(
             new FileOutputStream(currentFileName));
--------------------------------------------------------------------------------------------------------------------------------------
public void write(int b) throws IOException {
     super.write(b);
     // Tutaj nie jest wymagana adna aktualizacja,
     // poniewa automatycznie stosowany jest BufferedOutputStream.write()
     writer.write((byte)b);
}
--------------------------------------------------------------------------------------------------------------------------------------
public void reset() {
     super.reset();
     try {
         if (diffOutputStream != null) {
             diffOutputStream.flush();
             diffOutputStream.close();
             diffOutputStream = null;
         }
         if (writer != null) {
             writer.close();
         }
     } catch (IOException e) {
         e.printStackTrace();
      }
  }
  public void checkResult(int loopNumber) {
      try {
          writer.flush();
          writer.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
      check(validiationProperties.getProperty(propertyName));
      outProperties.put(propertyName, "" + getCRC());
      reset();
}
--------------------------------------------------------------------------------------------------------------------------------------
final private static Random generator = BailoutMain.random;
// pola tych klas zainicjowane w konstruktorze TaxCallable
final private TaxPayerBailoutDB db;
private String taxPayerId;
private long nullCounter;
private TaxPayerRecord updateTaxPayer(long iterations,
                                      TaxPayerRecord tpr) {
    if (iterations % 1001 == 0) {
        tpr = db.get(taxPayerId);
    } else {
        // aktualizacja rekordu bazy danych podatnikw
        tpr = db.get(taxPayerId);
        if (tpr != null) {
            long tax = generator.nextInt(10) + 15;
            tpr.taxPaid(tax);
        }
    }
    if (tpr == null) {
        nullCounter++;
    }
    return tpr;
}
--------------------------------------------------------------------------------------------------------------------------------------
private final AtomicLong seed;
private final static long multiplier = 0x5DEECE66DL;
private final static long addend = 0xBL;
private final static long mask = (1L << 48)  1;
protected int next(int bits) {
     long oldseed, nextseed;
     AtomicLong seed = this.seed;
     do {
       oldseed = seed.get();
       nextseed = (oldseed * multiplier + addend) & mask;
     } while (!seed.compareAndSet(oldseed, nextseed));
     return (int)(nextseed >>> (48 - bits));
 }
--------------------------------------------------------------------------------------------------------------------------------------
// Stara implementacja wykorzystujca statyczny obiekt Random
//final public static Random random =
//                    new Random(Thread.currentThread.getid());
// zostaa zastpiona przez new ThreadLocal<Random>
final public static ThreadLocal<Random> threadLocalRandom =
         new ThreadLocal<Random>() {
             @Override
             protected Random initialValue() {
                 return new Random(Thread.currentThread().getId());
             }
         };
--------------------------------------------------------------------------------------------------------------------------------------
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String, Map<String,TaxPayerRecord>> db;
    public TaxPayerBailoutDbImpl(int dbSize, int states) {
        db = new HashMap<String,Map<String,TaxPayerRecord>>(states);
        for (int i = 0; i < states; i++) {
            Map<String,TaxPayerRecord> map =
                Collections.synchronizedMap(
                    new HashMap<String,TaxPayerRecord>(dbSize/states));
            db.put(BailoutMain.states[i], map);
        }
    }
...
--------------------------------------------------------------------------------------------------------------------------------------
for (int i = 0; i < states; i++) {
    Map<String,TaxPayerRecord> map =
        Collections.synchronizedMap(
            new HashMap<String,TaxPayerRecord>(dbSize/states));
    db.put(BailoutMain.states[i], map);
}
--------------------------------------------------------------------------------------------------------------------------------------
char[] value;
int count;
public AbstractStringBuilder append(String str) {
  if (str == null) str = "null";
    int len = str.length();
  if (len == 0) return this;
  int newCount = count + len;
  if (newCount > value.length)
      expandCapacity(newCount);
  str.getChars(0, len, value, count);
  count = newCount;
  return this;
}
void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
    if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
    } else if (minimumCapacity > newCapacity) {
      newCapacity = minimumCapacity;
  }
    value = Arrays.copyOf(value, newCapacity);
}
--------------------------------------------------------------------------------------------------------------------------------------
public static String getRandomTaxPayerId() {
    StringBuilder sb = new StringBuilder(20);
    for (int i = 0; i < 20; i++) {
        int index =
            threadLocalRandom.get().nextInt(alphabet.length);
        sb.append(alphabet[index]);
    }
    return sb.toString();
}
public static String getRandomAddress() {
    StringBuilder sb = new StringBuilder(24);
    int size = threadLocalRandom.get().nextInt(14) + 10;
    for (int i = 0; i < size; i++) {
        if (i < 5) {
            int x = threadLocalRandom.get().nextInt(8);
            sb.append(x + 1);
        }
        int index =
             threadLocalRandom.get().nextInt(alphabet.length);
        char c = alphabet[index];
        if (i == 5) {
            c = Character.toUpperCase(c);
        }
        sb.append(c);
    }
    return sb.toString();
}
--------------------------------------------------------------------------------------------------------------------------------------
private final Map<String, Map<String,TaxPayerRecord>> db;
public TaxPayerBailoutDbImpl(int numberOfStates) {
     db = new HashMap<String,Map<String,TaxPayerRecord>>();
     for (int i = 0; i < numberOfStates; i++) {
         Map<String,TaxPayerRecord> map =
                 Collections.synchronizedMap(
                     new HashMap<String,TaxPayerRecord>());
         db.put(BailoutMain.states[i], map);
     }
}
--------------------------------------------------------------------------------------------------------------------------------------
static final int DEFAULT_INITIAL_CAPACITY = 16;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold =
               (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
    }
    void init() {
    }
--------------------------------------------------------------------------------------------------------------------------------------
private final Map<String, Map<String,TaxPayerRecord>> db;
private final int dbSize = 2000000;
public TaxPayerBailoutDbImpl(int dbSize, int numberOfStates) {
     final int outerMapSize = (int) Math.ceil(numberOfStates / .75);
     final int innerMapSize =
             (int) (Math.ceil((dbSize / numberOfStates) / .75));
     db =
        new HashMap<String,Map<String,TaxPayerRecord>>(outerMapSize);
     for (int i = 0; i < numberOfStates; i++) {
         Map<String,TaxPayerRecord> map =
              Collections.synchronizedMap(
                  new HashMap<String,TaxPayerRecord>(innerMapSize));
         db.put(BailoutMain.states[i], map);
     }
}
--------------------------------------------------------------------------------------------------------------------------------------
// alokowanie bazy danych
TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
// alokowanie listy przechowujcej nazwiska podatnikw
List<String>[] taxPayerList = new ArrayList[numberOfThreads];
for (int i = 0; i < numberOfThreads; i++) {
    taxPayerList[i] = new ArrayList<String>(taxPayerListSize);
}
// zapenianie bazy danych oraz listy podatnikw losowymi rekordami
populateDatabase(db, taxPayerList, dbSize);
...
private static void populateDatabase(TaxPayerBailoutDB db,
                                     List<String>[] taxPayerIdList,
                                     int dbSize) {
    for (int i = 0; i < dbSize; i++) {
        // tworzenie losowego id oraz rekordu podatnika
        String key = getRandomTaxPayerId();
        TaxPayerRecord tpr = makeTaxPayerRecord();
        // dodawanie losowego id oraz rekordu podatnika do bazy danych
        db.add(key, tpr);
        // dodawanie id podatnika do listy podatnikw
        int index = i % taxPayerIdList.length;
        taxPayerIdList[index].add(key);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
// alokowanie bazy danych
TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
List<String>[] taxPayerList = new List[numberOfThreads];
for (int i = 0; i < numberOfThreads; i++) {
    taxPayerList[i] =
            Collections.synchronizedList(
                new ArrayList<String>(taxPayerListSize));
}
// tworzenie puli egzekutorw do wykonania niektrych obiektw Callables
int numberOfThreads = System.availableProcessors();
ExecutorService pool =
    Executors.newFixedThreadPool(numberOfThreads);
Callable<DbInitializerFuture>[] dbCallables =
    new DbInitializer[numberOfThreads];
for (int i = 0; i < dbCallables.length; i++) {
    dbCallables[i] =
        new DbInitializer(db, taxPayerList, dbSize/numberOfThreads);
}
// uruchomienie wszystkich wtkw inicjalizatora bazy danych
Set<Future<DbInitializerFuture>> dbSet =
     new HashSet<Future<DbInitializerFuture>>();
for (int i = 0; i < dbCallables.length; i++) {
    Callable<DbInitializerFuture> callable = dbCallables[i];
    Future<DbInitializerFuture> future = pool.submit(callable);
    dbSet.add(future);
}
// Obiekt Callable, ktry wykona wielowtkow inicjacj bazy danych
public class DbInitializer implements Callable<DbInitializerFuture> {
    private TaxPayerBailoutDB db;
    private List<String>[] taxPayerList;
    private int recordsToCreate;
    public DbInitializer(TaxPayerBailoutDB db,
                         List<String>[] taxPayerList,
                         int recordsToCreate) {
        this.db = db;
        this.taxPayerList = taxPayerList;
        this.recordsToCreate = recordsToCreate;
    }
    @Override
    public DbInitializerFuture call() throws Exception {
        return BailoutMain.populateDatabase(db, taxPayerList,
                                            recordsToCreate);
    }
}
static DbInitializerFuture populateDatabase(TaxPayerBailoutDB db,
                                   List<String>[] taxPayerIdList,
                                   int dbSize) {
    for (int i = 0; i < dbSize; i++) {
        String key = getRandomTaxPayerId();
        TaxPayerRecord tpr = makeTaxPayerRecord();
        db.add(key, tpr);
        int index = i % taxPayerIdList.length;
        taxPayerIdList[index].add(key);
    }
    DbInitializerFuture future = new DbInitializerFuture();
    future.addToRecordsCreated(dbSize);
    return future;
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy rywalizacj o blokady.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
 
    final public static int TEST_TIME = 240 * 1000;
    final public static Random random = 
          new Random(Thread.currentThread().getId());
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v', 'w', 'x',
        'y', 'z'};
    private static String[] states = {"Alabama", "Alaska", "Arizona",
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final int numberOfThreads =
                        Runtime.getRuntime().availableProcessors();
        final int dbSize = TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw, ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenienie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
        List<String>[] taxPayerList = new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] = new ArrayList<String>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        System.out.println("\tBaza danych podatnikw zostaa utworzona.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
                    // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
               Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables = 
               new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
 
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set = 
                new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
            Future<BailoutFuture> future = pool.submit(callable);
            set.add(future);
        }
 
        System.out.println("\t(" + callables.length + 
                           ") wtki zostay uruchomione.");
        // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje 
        System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                           " sekund (" + callables.length + 
                           ") na zakoczenie wtkw ...");
 
        double iterationsPerSecond = 0;
        long recordsAdded = 0, recordsRemoved = 0;
        long nullCounter = 0;  int counter = 1;
        for (Future<BailoutFuture> future : set) {
            BailoutFuture result = null;
            try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                        Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                        Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                               counter++ + "] -> " +
                               result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
                    // podaje czn liczb elementw lub operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund -> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ---------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw -------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ---------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
 
        System.exit(0);
    }
 
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
                     List<String>[] taxPayerIdList, int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String key = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(key, tpr);
            int index = i % taxPayerIdList.length;
            taxPayerIdList[index].add(key);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            int index = random.nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = random.nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index = random.nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
    sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = random.nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
 
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder();
        int size = random.nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = random.nextInt(8);
                sb.append(x + 1);
            }
            int index = random.nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = random.nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index = random.nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = random.nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika lub zero jeli identyfikator nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String,TaxPayerRecord> db;
 
    public TaxPayerBailoutDbImpl(int size) {
        db = Collections.synchronizedMap(
                 new HashMap<String,TaxPayerRecord>(size));
    }
 
    @Override
    public TaxPayerRecord get(String id) {
        return db.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        TaxPayerRecord old = db.put(id, record);
        if (old != null) {
            // przywraca stary TaxPayerRecord
            old = db.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id) {
        return db.remove(id);
    }
 
    @Override
    public int size() {
        return db.size();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static Random generator = BailoutMain.random;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private String taxPayerId;
    final private List<String> taxPayerList;
final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<String> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            // Na wypadek przekroczenia maksymalnej liczby iteracji
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                        iterations / ((double) (elapsed / 1000));
                System.err.println(
                       "Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                       "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println(
                       "Liczba iteracji na sekund: " + iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(taxPayerId);
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(taxPayerId);
            if (tpr != null) {
                long tax = generator.nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(taxPayerId);
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            taxPayerList.add(tmpTaxPayerId);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    public void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.taxPayerId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy rywalizacj o blokady.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
final public static int TEST_TIME = 240 * 1000;
    final public static Random random = 
          new Random(Thread.currentThread().getId());
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v', 'w', 'x',
        'y', 'z'};
    private static String[] states = {"Alabama", "Alaska", "Arizona",
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final int numberOfThreads =
                        Runtime.getRuntime().availableProcessors();
        final int dbSize = TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw...");
        TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
        List<String>[] taxPayerList = new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] = new ArrayList<String>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        System.out.println("\tBaza danych podatnikw zostaa utworzona.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
 
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
               Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables = 
               new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
 
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set = 
                new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
            Future<BailoutFuture> future = pool.submit(callable);
            set.add(future);
        }
 
        System.out.println("\t(" + callables.length + 
                           ") wtki zostay uruchomione.");
        // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje
        System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                           " sekund (" + callables.length + 
                           ") na zakoczenie wtkw ...");
 
        double iterationsPerSecond = 0;
        long recordsAdded = 0, recordsRemoved = 0;
        long nullCounter = 0;  int counter = 1;
        for (Future<BailoutFuture> future : set) {
            BailoutFuture result = null;
            try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                        Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                        Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                               counter++ + "] -> " +
                               result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czn liczb elementw lub operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund -> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ---------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw -------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ---------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
 
        System.exit(0);
    }
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
                     List<String>[] taxPayerIdList, int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String key = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(key, tpr);
            int index = i % taxPayerIdList.length;
            taxPayerIdList[index].add(key);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            int index = random.nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = random.nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index = random.nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = random.nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder();
        int size = random.nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = random.nextInt(8);
                sb.append(x + 1);
            }
            int index = random.nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = random.nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index = random.nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = random.nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika lub zero jeli interfejs nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String,TaxPayerRecord> db;
 
    public TaxPayerBailoutDbImpl(int size) {
        db = new ConcurrentHashMap<String,TaxPayerRecord>(size);
    }
 
    @Override
    public TaxPayerRecord get(String id) {
        return db.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        TaxPayerRecord old = db.put(id, record);
        if (old != null) {
            // przywraca stary TaxPayerRecord
            old = db.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id) {
        return db.remove(id);
    }
 
    @Override
    public int size() {
        return db.size();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static Random generator = BailoutMain.random;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private String taxPayerId;
    final private List<String> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<String> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            // Na wypadek przekroczenia maksymalnej liczby iteracji
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                        iterations / ((double) (elapsed / 1000));
                System.err.println(
                       "Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                       "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println(
                       "Liczba iteracji na sekund: " + iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(taxPayerId);
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(taxPayerId);
            if (tpr != null) {
                long tax = generator.nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(taxPayerId);
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            taxPayerList.add(tmpTaxPayerId);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    public void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.taxPayerId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy rywalizacj o blokady.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
 
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId());
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v', 'w', 'x',
        'y', 'z'};
    static String[] states = {"Alabama", "Alaska", "Arizona",
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final long start = System.nanoTime();
        final int numberOfThreads =
                        Runtime.getRuntime().availableProcessors();
        final int dbSize = TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
        List<String>[] taxPayerList = new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] = new ArrayList<String>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        final long initDbTime = System.nanoTime() - start;
        System.out.println("\tBaza danych zostaa utworzona i zapeniona " +
                           "in (" + initDbTime/(1000*1000) + ") ms.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
               Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables = 
               new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
 
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set = 
                new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
           Future<BailoutFuture> future = pool.submit(callable);
           set.add(future);
       }
       System.out.println("\t(" + callables.length + 
                          ") wtki zostay uruchomione.");
       // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje 
       System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                          " sekund (" + callables.length + 
                          ") na zakoczenie wtkw ...");
       double iterationsPerSecond = 0;
       long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
       int counter = 1;
       for (Future<BailoutFuture> future : set) {
           BailoutFuture result = null;
           try {
               result = future.get();
           } catch (InterruptedException ex) {
               Logger.getLogger(
                   BailoutMain.class.getName()).log(
                       Level.SEVERE, null, ex);
           } catch (ExecutionException ex) {
               Logger.getLogger(
                   BailoutMain.class.getName()).log(
                       Level.SEVERE, null, ex);
           }
           System.out.println("Liczba iteracji na sekund dla wtku[" +
                              counter++ + "] -> " +
                              result.getIterationsPerSecond());
           iterationsPerSecond += result.getIterationsPerSecond();
           recordsAdded += result.getRecordsAdded();
           recordsRemoved += result.getRecordsRemoved();
           nullCounter = result.getNullCounter();
       }
       // podaje czn liczb elementw lub operacji
       DecimalFormat df = new DecimalFormat("#.##");
       System.out.println("czna liczba iteracji na sekund --> " +
                          df.format(iterationsPerSecond));
       NumberFormat nf = NumberFormat.getInstance();
       System.out.println("czna liczba dodanych rekordw ----------> " +
                          nf.format(recordsAdded));
       System.out.println("czna liczba usunitych rekordw --------> " +
                          nf.format(recordsRemoved));
       System.out.println("czna liczba rekordw w bazie danych ----------> " +
                          nf.format(db.size()));
       System.out.println("czna liczba rekordw zerowych: " +
                          nf.format(nullCounter));
       System.exit(0);
   }
   public static TaxPayerRecord makeTaxPayerRecord() {
       String firstName = getRandomName();
       String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
            List<String>[] taxPayerIdList,
            int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String key = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(key, tpr);
            int index = i % taxPayerIdList.length;
            taxPayerIdList[index].add(key);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
       this.city = city;
       this.state = state;
       this.taxPaid = new AtomicLong(0);
   }
   public String getFirstName() {
       return firstName;
   }
   public void setFirstName(String firstName) {
       this.firstName = firstName;
   }
   public String getLastName() {
       return lastName;
   }
   public void setLastName(String lastName) {
       this.lastName = lastName;
   }
   public String getSsn() {
       return ssn;
   }
   public void setSsn(String ssn) {
       this.ssn = ssn;
   }
   public String getAddress() {
       return address;
   }
   public void setAddress(String address) {
       this.address = address;
   }
   public String getCity() {
       return city;
   }
   public void setCity(String city) {
       this.city = city;
   }
   public String getState() {
       return state;
   }
   public void setState(String state) {
       this.state = state;
   }
   public void taxPaid(long amount) {
       taxPaid.addAndGet(amount);
   }
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika lub zero jeli interfejs podatnika nie zosta znaleziony w bazie danych
     */
     TaxPayerRecord remove(String id);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String,TaxPayerRecord> db;
 
    public TaxPayerBailoutDbImpl(int size) {
        db = new ConcurrentHashMap<String,TaxPayerRecord>(size);
    }
 
    @Override
    public TaxPayerRecord get(String id) {
        return db.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        TaxPayerRecord old = db.put(id, record);
        if (old != null) {
            // przywraca stary TaxPayerRecord
            old = db.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id) {
        return db.remove(id);
    }
 
    @Override
    public int size() {
        return db.size();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
              BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private String taxPayerId;
    final private List<String> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<String> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            // Na wypadek przekroczenia maksymalnej liczby iteracji
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                        iterations / ((double) (elapsed / 1000));
                System.err.println(
                       "Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                       "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println(
                       "Liczba iteracji na sekund: " + iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(taxPayerId);
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(taxPayerId);
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnnika z bazy danych
        tpr = db.remove(taxPayerId);
        if (tpr != null) {
            // usuw rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            taxPayerList.add(tmpTaxPayerId);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    public void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.taxPayerId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy rywalizacj o blokady.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId());
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v', 'w', 'x',
        'y', 'z'};
    private static String[] states = {"Alabama", "Alaska", "Arizona",
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final int numberOfThreads =
                        Runtime.getRuntime().availableProcessors();
        final int dbSize = TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
        List<String>[] taxPayerList = new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] = new ArrayList<String>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        System.out.println("\tBaza danych podatnikw zostaa utworzona.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
 
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
               Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables = 
               new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
 
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set =
                new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
            Future<BailoutFuture> future = pool.submit(callable);
            set.add(future);
        }
 
        System.out.println("\t(" + callables.length + 
                           ") wtki zostay uruchomione.");
        // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje 
        System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                           " sekund (" + callables.length + 
                           ") na zakoczenie wtkw ...");
 
        double iterationsPerSecond = 0;
        long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
        int counter = 1;
        for (Future<BailoutFuture> future : set) {
            BailoutFuture result = null;
            try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                        Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                        Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                               counter++ + "] -> " +
                               result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czn liczb elementw lub operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund --> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ----------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw --------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw ----------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
 
        System.exit(0);
    }
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
                   List<String>[] taxPayerIdList, int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String key = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(key, tpr);
            int index = i % taxPayerIdList.length;
            taxPayerIdList[index].add(key);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
      this.address = address;
      this.city = city;
      this.state = state;
      this.taxPaid = new AtomicLong(0);
  }
  public String getFirstName() {
      return firstName;
  }
  public void setFirstName(String firstName) {
      this.firstName = firstName;
  }
  public String getLastName() {
      return lastName;
  }
  public void setLastName(String lastName) {
      this.lastName = lastName;
  }
  public String getSsn() {
      return ssn;
  }
  public void setSsn(String ssn) {
      this.ssn = ssn;
  }
  public String getAddress() {
      return address;
  }
  public void setAddress(String address) {
      this.address = address;
  }
  public String getCity() {
      return city;
  }
  public void setCity(String city) {
      this.city = city;
  }
  public String getState() {
      return state;
  }
  public void setState(String state) {
      this.state = state;
  }
  public void taxPaid(long amount) {
      taxPaid.addAndGet(amount);
  }
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika lub zero, jeli identyfikator nie zostal znaleziony w bazie
     */
     TaxPayerRecord remove(String id);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String,TaxPayerRecord> db;
    public TaxPayerBailoutDbImpl(int size) {
        db = Collections.synchronizedMap(
                 new HashMap<String,TaxPayerRecord>(size));
    }
 
    @Override
    public TaxPayerRecord get(String id) {
        return db.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        TaxPayerRecord old = db.put(id, record);
        if (old != null) {
            // przywraca stary TaxPayerRecord
            old = db.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id) {
        return db.remove(id);
    }
 
    @Override
    public int size() {
        return db.size();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
                                  BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private String taxPayerId;
    final private List<String> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<String> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            // Na wypadek przekroczenia maksymalnej liczby iteracji
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                        iterations / ((double) (elapsed / 1000));
                System.err.println(
                       "Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                       "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println(
                       "Liczba iteracji na sekund: " + iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(taxPayerId);
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(taxPayerId);
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(taxPayerId);
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            taxPayerList.add(tmpTaxPayerId);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    public void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.taxPayerId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy rywalizacj o blokady.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
 
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId())
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
                                      'g', 'h', 'i', 'j', 'k', 'l',
                                      'm', 'n', 'o', 'p', 'q', 'r',
                                      's', 't', 'u', 'v', 'w', 'x',
                                      'y', 'z'};
    static String[] states = {"Alabama", "Alaska", "Arizona", 
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan"
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska"
        "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final int numberOfThreads =
                Runtime.getRuntime().availableProcessors();
        final int dbSize =
                TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw ktre maj by wykonywane jednoczenie : "
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = 
                new TaxPayerBailoutDbImpl(dbSize, states.length);
        List<StateAndId>[] taxPayerList =
                new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] =
                    new ArrayList<StateAndId>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        System.out.println("\tBaza danych podatnikw zostaa utworzona.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
                Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables =
                new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set = 
                new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
            Future<BailoutFuture> future = pool.submit(callable);
            set.add(future);
        }
 
        System.out.println("\t(" + callables.length + 
                           ") wtki zostay uruchomione.");
        // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje 
        System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                           " sekund (" + callables.length + 
                           ") na zakoczenie wtkw ...");
 
        double iterationsPerSecond = 0;
        long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
        int counter = 1;
        for (Future<BailoutFuture> future : set) {
            BailoutFuture result = null;
            try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                                 Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                                 Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                               counter++ + "] -> " +
                               result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czn liczb elementw lub operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund --> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ----------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw --------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ----------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
 
        System.exit(0);
    }
 
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
                              List<StateAndId>[] taxPayerList,
                                                   int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String taxPayerId = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(taxPayerId, tpr);
            StateAndId stateAndId = 
                    new StateAndId(taxPayerId, tpr.getState());
            int index = i % taxPayerList.length;
            taxPayerList[index].add(stateAndId);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
 
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param taxPayersId - identyfikator podatnika
     * @param state - stan, w ktrym mieszka podatnik
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id, String state);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param taxPayersId - identyfikator podatnika
     * @param taxPayersState - stan, w ktrym mieszka podatnik
     * @return rekord podatnika lub zero, jeli identyfikator nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id, String state);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String, Map<String,TaxPayerRecord>> db;
 
    public TaxPayerBailoutDbImpl(int dbSize, int numberOfStates) {
        db = new HashMap<String,Map<String,TaxPayerRecord>>(dbSize);
        for (int i = 0; i < numberOfStates; i++) {
            Map<String,TaxPayerRecord> map =
                    Collections.synchronizedMap(
                        new HashMap<String,TaxPayerRecord>(
                            dbSize/numberOfStates));
            db.put(BailoutMain.states[i], map);
        }
    }
 
    @Override
    public TaxPayerRecord get(String id, String state) {
        Map<String,TaxPayerRecord> map = getStateMap(state);
        if (map == null) {
            System.out.println("Unable to find state: " + state);
        }
        return map.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        Map<String,TaxPayerRecord> map = getStateMap(record.getState());
        // Aktualizuje rekord podatnika jeli znajdzie
        TaxPayerRecord old = map.put(id, record);
        if (old != null) {
            // jeli nie znajdzie, przywraca stary TaxPayerRecord
            old = map.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id, String state) {
        Map<String,TaxPayerRecord> map = getStateMap(state);
        TaxPayerRecord tmpRecord = null;
        if (map != null)
            tmpRecord = map.remove(id);
        return tmpRecord;
    }
 
    @Override
    public int size() {
        int size = 0;
        Iterator<Map<String,TaxPayerRecord>> itr =
                                  db.values().iterator();
        while (itr.hasNext()) {
            Map<String,TaxPayerRecord> m = itr.next();
            if (m != null)
                size += m.size();
        }
        return size;
    }
 
    private Map<String, TaxPayerRecord> getStateMap(String state) {
        Map<String,TaxPayerRecord> map = db.get(state);
        if (map == null) {
            throw new UnsupportedOperationException(
                    "Stan (" + state + ") " +
                    "nie zosta odnaleziony w bazie danych podatnikw.");
        }
        return map;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
                                   BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private StateAndId stateAndId;
    final private List<StateAndId> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<StateAndId> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                       iterations / ((double) (elapsed / 1000));
                System.err.
                    println("Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                      "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println("Liczba iteracji na sekund: " +
                                   iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(stateAndId.getId(), stateAndId.getState());
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(stateAndId.getId(), stateAndId.getState());
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(stateAndId.getId(), stateAndId.getState());
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych 
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            StateAndId sai = 
                     new StateAndId(tmpTaxPayerId, tpr.getState());
            taxPayerList.add(sai);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    private void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.stateAndId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
final public class StateAndId {
    private String id;
    private String state;
 
    public StateAndId(String id, String state) {
        this.id = id; this.state = state;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public String getId() {
        return id;
    }
 
     public void setId(String id) {
        this.id = id;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy rywalizacj o blokady.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
 
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId());
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
                                      'g', 'h', 'i', 'j', 'k', 'l',
                                      'm', 'n', 'o', 'p', 'q', 'r',
                                      's', 't', 'u', 'v', 'w', 'x',
                                      'y', 'z'};
    static String[] states = {"Alabama", "Alaska", "Arizona", 
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final long start = System.nanoTime();
        final int numberOfThreads =
                Runtime.getRuntime().availableProcessors();
        final int dbSize =
                TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw, ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = 
                new TaxPayerBailoutDbImpl(dbSize, states.length);
        List<StateAndId>[] taxPayerList =
                new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] =
                    new ArrayList<StateAndId>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        final long initDbTime = System.nanoTime() - start;
      System.out.println("\tBaza danych podatnikw zostaa utworzone i zapeniona" +
                         " w cigu (" + initDbTime/(1000*1000) + ") ms.");
      System.out.println("Alokacja (" + numberOfThreads + 
                         ") wtkw ...");
      // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
      ExecutorService pool =
              Executors.newFixedThreadPool(numberOfThreads);
      Callable<BailoutFuture>[] callables =
              new TaxCallable[numberOfThreads];
      for (int i = 0; i < callables.length; i++) {
          callables[i] = new TaxCallable(taxPayerList[i], db);
      }
      System.out.println("\tWtki zostay alokowane.");
      // rozpoczyna wykonywanie wszystkich wtkw
      System.out.println("Uruchamianie (" + callables.length + 
                         ") wtkw ...");
      Set<Future<BailoutFuture>> set = 
              new HashSet<Future<BailoutFuture>>();
      for (int i = 0; i < callables.length; i++) {
          Callable<BailoutFuture> callable = callables[i];
          Future<BailoutFuture> future = pool.submit(callable);
          set.add(future);
      }
      System.out.println("\t(" + callables.length + 
                         ") wtki zostay uruchomione.");
      // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje 
      System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                         " sekund (" + callables.length + 
                         ") na zakoczenie wtkw ...");
      double iterationsPerSecond = 0;
      long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
      int counter = 1;
      for (Future<BailoutFuture> future : set) {
          BailoutFuture result = null;
          try {
              result = future.get();
          } catch (InterruptedException ex) {
              Logger.getLogger(
                  BailoutMain.class.getName()).log(
                               Level.SEVERE, null, ex);
          } catch (ExecutionException ex) {
              Logger.getLogger(
                  BailoutMain.class.getName()).log(
                               Level.SEVERE, null, ex);
          }
          System.out.println("Liczba iteracji na sekund dla wtku[" +
                             counter++ + "] -> " +
                             result.getIterationsPerSecond());
          iterationsPerSecond += result.getIterationsPerSecond();
          recordsAdded += result.getRecordsAdded();
          recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czn liczb elementw i operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund --> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ----------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw --------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ----------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
 
        System.exit(0);
    }
 
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
                              List<StateAndId>[] taxPayerList,
                                                   int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String taxPayerId = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(taxPayerId, tpr);
            StateAndId stateAndId = 
                    new StateAndId(taxPayerId, tpr.getState());
            int index = i % taxPayerList.length;
            taxPayerList[index].add(stateAndId);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
 
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param taxPayersId - identyfikator podatnika
     * @param state - stan, w ktrym mieszka podatnik
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id, String state);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param taxPayersId - identyfikator podatnika
     * @param taxPayersState - stan, w ktrym mieszka podatnik
     * @return rekord podatnika lub zero, jeli identyfikator nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id, String state);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String, Map<String,TaxPayerRecord>> db;
 
    public TaxPayerBailoutDbImpl(int dbSize, int numberOfStates) {
        db = new HashMap<String,Map<String,TaxPayerRecord>>(dbSize);
        for (int i = 0; i < numberOfStates; i++) {
            Map<String,TaxPayerRecord> map =
                    Collections.synchronizedMap(
                        new HashMap<String,TaxPayerRecord>(
                            dbSize/numberOfStates));
            db.put(BailoutMain.states[i], map);
        }
    }
 
    @Override
    public TaxPayerRecord get(String id, String state) {
        Map<String,TaxPayerRecord> map = getStateMap(state);
        if (map == null) {
            System.out.println("Unable to find state: " + state);
        }
        return map.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        Map<String,TaxPayerRecord> map = getStateMap(record.getState());
        // aktualizuje rekord podatnika jeli znajdzie
        TaxPayerRecord old = map.put(id, record);
        if (old != null) {
            // jeli nie znajdzie, przywraca stary TaxPayerRecord
            old = map.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id, String state) {
        Map<String,TaxPayerRecord> map = getStateMap(state);
        TaxPayerRecord tmpRecord = null;
        if (map != null)
            tmpRecord = map.remove(id);
        return tmpRecord;
    }
 
    @Override
    public int size() {
        int size = 0;
        Iterator<Map<String,TaxPayerRecord>> itr =
                                  db.values().iterator();
        while (itr.hasNext()) {
            Map<String,TaxPayerRecord> m = itr.next();
            if (m != null)
                size += m.size();
        }
        return size;
    }
 
    private Map<String, TaxPayerRecord> getStateMap(String state) {
        Map<String,TaxPayerRecord> map = db.get(state);
        if (map == null) {
            throw new UnsupportedOperationException(
                    "Stan (" + state + ") " +
                    "nie zosta znaleziony w bazie danych podatnikw.");
        }
        return map;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
                                   BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private StateAndId stateAndId;
    final private List<StateAndId> taxPayerList;
    final private TaxPayerBailoutDB db;
    public TaxCallable(List<StateAndId> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                       iterations / ((double) (elapsed / 1000));
                System.err.
                    println("Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                      "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println("Liczba iteracji na sekund: " +
                                   iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(stateAndId.getId(), stateAndId.getState());
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(stateAndId.getId(), stateAndId.getState());
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(stateAndId.getId(), stateAndId.getState());
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            StateAndId sai = 
                     new StateAndId(tmpTaxPayerId, tpr.getState());
            taxPayerList.add(sai);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    private void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.stateAndId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
final public class StateAndId {
    private String id, state;
 
    public StateAndId(String id, String state) {
        this.id = id; this.state = state;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public String getId() {
        return id;
    }
 
     public void setId(String id) {
        this.id = id;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
/**
 * Przykadowy program ilustrujcy wpyw zmiany rozmiaru Java Collections na wydajno.
 */
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId());
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
                                      'g', 'h', 'i', 'j', 'k', 'l',
                                      'm', 'n', 'o', 'p', 'q', 'r',
                                      's', 't', 'u', 'v', 'w', 'x',
                                      'y', 'z'};
    static String[] states = {"Alabama", "Alaska", "Arizona", 
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
    public static void main(String[] args) {
        final long start = System.nanoTime();
        final int numberOfThreads =
                Runtime.getRuntime().availableProcessors();
        final int dbSize =
                TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw, ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = 
                new TaxPayerBailoutDbImpl(dbSize, states.length);
        List<StateAndId>[] taxPayerList =
                new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] =
                    new ArrayList<StateAndId>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        final long initDbTime = System.nanoTime() - start;
        System.out.println("\tBaza danych podatnikw zostaa utworzona i " +
                           "zapeniona w cigu (" +
                           initDbTime/(1000*1000) + ") ms.");
        System.out.println("\tBaza danych podatnikw zostaa utworzona.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
                Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables =
                new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
 
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set = 
                new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
            Future<BailoutFuture> future = pool.submit(callable);
            set.add(future);
        }
 
        System.out.println("\t(" + callables.length + 
                           ") wtki zostay uruchomione.");
        // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje
        System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                           " sekund (" + callables.length + 
                           ") na zakoczenie wtkw ...");
 
        double iterationsPerSecond = 0;
        long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
        int counter = 1;
        for (Future<BailoutFuture> future : set) {
            BailoutFuture result = null;
            try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                                 Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(
                    BailoutMain.class.getName()).log(
                                 Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                               counter++ + "] -> " +
                               result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czn liczb elementw lub operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund --> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ----------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw --------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ----------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
 
        System.exit(0);
    }
 
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
    private static void populateDatabase(TaxPayerBailoutDB db,
                              List<StateAndId>[] taxPayerList,
                                                   int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String taxPayerId = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(taxPayerId, tpr);
            StateAndId stateAndId = 
                    new StateAndId(taxPayerId, tpr.getState());
            int index = i % taxPayerList.length;
            taxPayerList[index].add(stateAndId);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder(20);
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                 threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
 
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder(24);
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param taxPayersId - identyfikator podatnika
     * @param state - stan, w ktrym mieszka podatnik
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id, String state);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param taxPayersId - identyfikator podatnika
     * @param taxPayersState - stan, w ktrym mieszka podatnik
     * @return rekord podatnika lub zero, jeli identyfikator nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id, String state);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String, Map<String,TaxPayerRecord>> db;
 
    public TaxPayerBailoutDbImpl(int dbSize, int numberOfStates) {
        final int outerMapSize = (int) Math.ceil(numberOfStates / .75);
        final int innerMapSize =
                (int) (Math.ceil((dbSize / numberOfStates) / .75));
        db = 
         new HashMap<String,Map<String,TaxPayerRecord>>(outerMapSize);
        for (int i = 0; i < numberOfStates; i++) {
            Map<String,TaxPayerRecord> map =
                Collections.synchronizedMap(
                   new HashMap<String,TaxPayerRecord>(innerMapSize));
            db.put(BailoutMain.states[i], map);
        }
    }
 
    @Override
    public TaxPayerRecord get(String id, String state) {
        Map<String,TaxPayerRecord> map = getStateMap(state);
        if (map == null) {
            System.out.println("Nie mona odnale stanu: " + state);
        }
        return map.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        Map<String,TaxPayerRecord> map = getStateMap(record.getState());
        // aktualizuj rekord podatnika, jeli znajdziesz
        TaxPayerRecord old = map.put(id, record);
        if (old != null) {
            // jeli nie znajdziesz, przywr stary TaxPayerRecord
            old = map.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id, String state) {
        Map<String,TaxPayerRecord> map = getStateMap(state);
        TaxPayerRecord tmpRecord = null;
        if (map != null)
            tmpRecord = map.remove(id);
        return tmpRecord;
    }
 
    @Override
    public int size() {
        int size = 0;
        Iterator<Map<String,TaxPayerRecord>> itr =
                                  db.values().iterator();
        while (itr.hasNext()) {
            Map<String,TaxPayerRecord> m = itr.next();
            if (m != null)
                size += m.size();
        }
        return size;
    }
 
    private Map<String, TaxPayerRecord> getStateMap(String state) {
        Map<String,TaxPayerRecord> map = db.get(state);
        if (map == null) {
            throw new UnsupportedOperationException(
                    "Stan (" + state + ") " +
                    "nie zosta odnaleziony w bazie danych podatnikw.");
        }
        return map;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
                                   BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private StateAndId stateAndId;
    final private List<StateAndId> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<StateAndId> taxPayerList,
                       TaxPayerBailoutDB db) {
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = 
                       iterations / ((double) (elapsed / 1000));
                System.err.
                    println("Licznik iteracji jest bliski przekroczenia ...");
                System.err.println(
                      "Obliczanie liczby biecych operacji na sekund ...");
                System.err.println("Liczba iteracji na sekund: " +
                                   iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = 
                    iterations / ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(stateAndId.getId(), stateAndId.getState());
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(stateAndId.getId(), stateAndId.getState());
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(stateAndId.getId(), stateAndId.getState());
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            StateAndId sai = 
                     new StateAndId(tmpTaxPayerId, tpr.getState());
            taxPayerList.add(sai);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    private void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.stateAndId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
final public class StateAndId {
    private String id, state;
 
    public StateAndId(String id, String state) {
        this.id = id; this.state = state;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
 
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId());
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
    static String[] states = {"Alabama", "Alaska", "Arizona",
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas",
        "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final long start = System.nanoTime();
        final int numberOfThreads =
            Runtime.getRuntime().availableProcessors();
        final int dbSize =
            TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw, ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych podatnikw
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
        List<String>[] taxPayerList = new ArrayList[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] = new ArrayList<String>(taxPayerListSize);
        }
        populateDatabase(db, taxPayerList, dbSize);
        final long initDbTime = System.nanoTime() - start;
        System.out.println("\tBaza danych zostaa utworzona i zapeniona w cigu (" +
                           initDbTime/(1000*1000) + ") ms.");
 
        System.out.println("Alokacja (" + numberOfThreads + 
                           ") wtkw ...");
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
            Executors.newFixedThreadPool(numberOfThreads);
 
        Callable<BailoutFuture>[] callables = 
            new TaxCallable[numberOfThreads];
        for (int i = 0; i < callables.length; i++) {
            callables[i] = new TaxCallable(taxPayerList[i], db);
        }
        System.out.println("\tWtki zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw
        System.out.println("Uruchamianie (" + callables.length + 
                           ") wtkw ...");
        Set<Future<BailoutFuture>> set = 
            new HashSet<Future<BailoutFuture>>();
        for (int i = 0; i < callables.length; i++) {
            Callable<BailoutFuture> callable = callables[i];
            Future<BailoutFuture> future = pool.submit(callable);
            set.add(future);
        }
 
        System.out.println("\t(" + callables.length + 
                           ") wtki zostay uruchomione.");
        // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje
        System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                           " sekund (" + callables.length + 
                           ") na zakoczenie wtkw ...");
 
        double iterationsPerSecond = 0;
        long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
        int counter = 1;
        for (Future<BailoutFuture> future : set) {
            BailoutFuture result = null;
            try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(BailoutMain.class.getName())
                      .log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(BailoutMain.class.getName())
                      .log(Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                               counter++ + "] -> " +
                               result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czn liczb elementw lub operacji 
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund --> " +
                           df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ----------> " +
                           nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw --------> " +
                           nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ----------> " +
                           nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
                           nf.format(nullCounter));
        System.exit(0);
    }
 
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    private static void populateDatabase(TaxPayerBailoutDB db,
                     List<String>[] taxPayerIdList, int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String key = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(key, tpr);
            int index = i % taxPayerIdList.length;
            taxPayerIdList[index].add(key);
        }
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder(20);
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
 
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder(24);
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobieranie z bazy danych rekordu podatnika na podstawie jego/jej identyfikatora.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika lub zero, jeli identyfikator nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String,TaxPayerRecord> db;
    public TaxPayerBailoutDbImpl(int size) {
        db = new ConcurrentHashMap<String,TaxPayerRecord>(size);
    }
 
    @Override
    public TaxPayerRecord get(String id) {
        return db.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        TaxPayerRecord old = db.put(id, record);
        if (old != null) {
            // przywraca start TaxPayerRecord
            old = db.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id) {
        return db.remove(id);
    }
 
    @Override
    public int size() {
        return db.size();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
                                    BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private String taxPayerId;
    final private List<String> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<String> taxPayerList, TaxPayerBailoutDB db){
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = iterations / 
                                          ((double) (elapsed / 1000));
                System.err.println("Przekroczenie licznika iteracji ...");
                System.err.println("Obliczanie liczby biecych operacji na sekund.");
                System.err.println("Liczba operacji na sekund: " + 
                                   iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = iterations / 
                                  ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(taxPayerId);
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(taxPayerId);
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(taxPayerId);
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            taxPayerList.add(tmpTaxPayerId);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    public void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.taxPayerId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BailoutMain {
    final public static int TEST_TIME = 240 * 1000;
    final public static ThreadLocal<Random> threadLocalRandom =
            new ThreadLocal<Random>() {
                @Override
                protected Random initialValue() {
                    return new Random(Thread.currentThread().getId());
                }
            };
    private static char[] alphabet = {'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
    static String[] states = {"Alabama", "Alaska", "Arizona",
        "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska",
        "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah",
        "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming"};
 
    public static void main(String[] args) {
        final long start = System.nanoTime();
        final int numberOfThreads =
            Runtime.getRuntime().availableProcessors();
        final int dbSize = TaxPayerBailoutDB.NUMBER_OF_RECORDS_DESIRED;
        final int taxPayerListSize = dbSize / numberOfThreads;
 
        System.out.println("Liczba wtkw, ktre maj by wykonywane jednoczenie : " +
                           numberOfThreads);
        System.out.println("Rozmiar bazy danych podatnikw: " + dbSize);
 
        // zapenianie bazy danych rekordami
        System.out.println("Tworzenie bazy danych podatnikw ...");
        TaxPayerBailoutDB db = new TaxPayerBailoutDbImpl(dbSize);
        List<String>[] taxPayerList = new List[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++) {
            taxPayerList[i] =
                    Collections.synchronizedList(
                        new ArrayList<String>(taxPayerListSize));
        }
 
        System.out.println("Alokowanie puli wtkw oraz (" +
            numberOfThreads + ") oraz wtkw inicjalizatora bazy danych ...");
 
        // tworzenie puli egzekutorw do wykonania niektrych interfejsw Callable
        ExecutorService pool =
            Executors.newFixedThreadPool(numberOfThreads);
        Callable<DbInitializerFuture>[] dbCallables = 
            new DbInitializer[numberOfThreads];
        for (int i = 0; i < dbCallables.length; i++) {
            dbCallables[i] = 
                new DbInitializer(db, taxPayerList,
                                  dbSize/numberOfThreads);
        }
 
        System.out.println("\tPula wtkw oraz wtki bazy danych zostay alokowane.");
 
        // rozpoczyna wykonywanie wszystkich wtkw inicjalizatora bazy danych
        System.out.println("Uruchamianie (" + dbCallables.length + 
                           ") wtkw inicjalizatora bazy danych ...");
        Set<Future<DbInitializerFuture>> dbSet = 
            new HashSet<Future<DbInitializerFuture>>();
        for (int i = 0; i < dbCallables.length; i++) {
            Callable<DbInitializerFuture> callable = dbCallables[i];
            Future<DbInitializerFuture> future = pool.submit(callable);
            dbSet.add(future);
        }
       int recordsCreated = 0;
       for (Future<DbInitializerFuture> future : dbSet) {
           DbInitializerFuture result = null;
           try {
               result = future.get();
           } catch (InterruptedException ex) {
               Logger.getLogger(BailoutMain.class.getName())
                     .log(Level.SEVERE, null, ex);
           } catch (ExecutionException ex) {
               Logger.getLogger(BailoutMain.class.getName())
                     .log(Level.SEVERE, null, ex);
           }
           recordsCreated += result.getRecordsCreated();
       }
       final long initDbTime = System.nanoTime() - start;
       System.out.println("\tWtki inicjalizatora bazy danych zostay zakoczone.");
       System.out.println("\tBaza danych podatnikw utworzona i zapeniona w cigu (" +
                          initDbTime/(1000*1000) + ") ms.");
       System.out.println("\tUtworzono (" + recordsCreated + 
                          ") rekordw ...");
       System.out.println("Alokacja wtkw, gwne przetwarzanie ...");
       Callable<BailoutFuture>[] callables = 
           new TaxCallable[numberOfThreads];
       for (int i = 0; i < callables.length; i++) {
           callables[i] = new TaxCallable(taxPayerList[i], db);
       }
       System.out.println("\tWtki zostay alokowane.");
       // rozpoczyna uruchamianie wszystkich wtkw
       System.out.println("Uruchamianie (" + callables.length + 
                          ") wtkw ...");
       Set<Future<BailoutFuture>> set = 
           new HashSet<Future<BailoutFuture>>();
       for (int i = 0; i < callables.length; i++) {
           Callable<BailoutFuture> callable = callables[i];
           Future<BailoutFuture> future = pool.submit(callable);
           set.add(future);
       }
       System.out.println("\t(" + callables.length + 
                          ") wtki zostay uruchomione.");
       // blokowanie i oczekiwanie, aby wszystkie interfejsy Callable zakoczyy swoje operacje
       System.out.println("Oczekiwanie przez " + TEST_TIME / 1000 + 
                          " sekund (" + callables.length + 
                          ") na zakoczenie wtkw ...");
       double iterationsPerSecond = 0;
       long recordsAdded = 0, recordsRemoved = 0, nullCounter = 0;
       int counter = 1;
       for (Future<BailoutFuture> future : set) {
           BailoutFuture result = null;
           try {
                result = future.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(BailoutMain.class.getName())
                      .log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(BailoutMain.class.getName())
                      .log(Level.SEVERE, null, ex);
            }
            System.out.println("Liczba iteracji na sekund dla wtku[" +
                counter++ + "] -> " + result.getIterationsPerSecond());
            iterationsPerSecond += result.getIterationsPerSecond();
            recordsAdded += result.getRecordsAdded();
            recordsRemoved += result.getRecordsRemoved();
            nullCounter = result.getNullCounter();
        }
 
        // podaje czna liczb elementw lub operacji
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("czna liczba iteracji na sekund --> " +
            df.format(iterationsPerSecond));
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println("czna liczba dodanych rekordw ----------> " +
            nf.format(recordsAdded));
        System.out.println("czna liczba usunitych rekordw --------> " +
            nf.format(recordsRemoved));
        System.out.println("czna liczba rekordw w bazie danych ----------> " +
            nf.format(db.size()));
        System.out.println("czna liczba rekordw zerowych: " +
            nf.format(nullCounter));
 
        System.exit(0);
    }
 
    public static TaxPayerRecord makeTaxPayerRecord() {
        String firstName = getRandomName();
        String lastName = getRandomName();
        String ssn = getRandomSSN();
        String address = getRandomAddress();
        String city = getRandomCity();
        String state = getRandomState();
        return new TaxPayerRecord(firstName, lastName, ssn,
                address, city, state);
    }
 
    static DbInitializerFuture populateDatabase(TaxPayerBailoutDB db,
                                         List<String>[] taxPayerIdList,
                                         int dbSize) {
        for (int i = 0; i < dbSize; i++) {
            String key = getRandomTaxPayerId();
            TaxPayerRecord tpr = makeTaxPayerRecord();
            db.add(key, tpr);
            int index = i % taxPayerIdList.length;
            taxPayerIdList[index].add(key);
        }
        DbInitializerFuture future = new DbInitializerFuture();
        future.addToRecordsCreated(dbSize);
        return future;
    }
 
    public static String getRandomTaxPayerId() {
        StringBuilder sb = new StringBuilder(20);
        for (int i = 0; i < 20; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            sb.append(alphabet[index]);
        }
        return sb.toString();
    }
 
    public static String getRandomName() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(8) + 5;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomSSN() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 11; i++) {
            if (i == 3 || i == 6) {
                sb.append('-');
            }
            int x = threadLocalRandom.get().nextInt(9);
            sb.append(x);
        }
        return sb.toString();
    }
 
    public static String getRandomAddress() {
        StringBuilder sb = new StringBuilder(24);
        int size = threadLocalRandom.get().nextInt(14) + 10;
        for (int i = 0; i < size; i++) {
            if (i < 5) {
                int x = threadLocalRandom.get().nextInt(8);
                sb.append(x + 1);
            }
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 5) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomCity() {
        StringBuilder sb = new StringBuilder();
        int size = threadLocalRandom.get().nextInt(5) + 6;
        for (int i = 0; i < size; i++) {
            int index =
                threadLocalRandom.get().nextInt(alphabet.length);
            char c = alphabet[index];
            if (i == 0) {
                c = Character.toUpperCase(c);
            }
            sb.append(c);
        }
        return sb.toString();
    }
 
    public static String getRandomState() {
        int index = threadLocalRandom.get().nextInt(states.length);
        return states[index];
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.concurrent.Callable;
 
public class DbInitializer implements Callable<DbInitializerFuture> {
 
    private TaxPayerBailoutDB db;
    private List<String>[] taxPayerList;
    private int recordsToCreate;
 
    public DbInitializer(TaxPayerBailoutDB db,
                         List<String>[] taxPayerList,
                         int recordsToCreate) {
        this.db = db;
        this.taxPayerList = taxPayerList;
        this.recordsToCreate = recordsToCreate;
    }
 
    @Override
    public DbInitializerFuture call() throws Exception {
        return BailoutMain.populateDatabase(db, taxPayerList,
                                            recordsToCreate);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class DbInitializerFuture {
    private int recordsCreated;
 
    public DbInitializerFuture() {}
 
    public void addToRecordsCreated(int value) {
        recordsCreated += value;
    }
 
    public int getRecordsCreated() {
        return recordsCreated;
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.atomic.AtomicLong;
 
public class TaxPayerRecord {
    private String firstName, lastName, ssn, address, city, state;
    private AtomicLong taxPaid;
 
    public TaxPayerRecord(String firstName, String lastName, String ssn,
                          String address, String city, String state) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.ssn = ssn;
        this.address = address;
        this.city = city;
        this.state = state;
        this.taxPaid = new AtomicLong(0);
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getSsn() {
        return ssn;
    }
 
    public void setSsn(String ssn) {
        this.ssn = ssn;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
 
    public void taxPaid(long amount) {
        taxPaid.addAndGet(amount);
    }
 
    public long getTaxPaid() {
        return taxPaid.get();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public interface TaxPayerBailoutDB {
 
    static final int NUMBER_OF_RECORDS_DESIRED = 2 * 1000000;
 
    /**
     * Pobiera z bazy danych rekord podatnika na podstawie jego/jej identyfikatora.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika
     */
     TaxPayerRecord get(String id);
 
    /**
     * Dodaje nowy rekord podatnika w bazie danych.
     *
     * @param id - identyfikator podatnika
     * @param record - rekord podatnika
     * @return taxPayersRecord dodany wanie do bazy danych
     */
     TaxPayerRecord add(String id,  TaxPayerRecord record);
 
    /**
     * Usuwa rekord podatnika z bazy danych.
     *
     * @param id - identyfikator podatnika
     * @return rekord podatnika lub zero, jeli identyfikator nie zosta znaleziony w bazie
     */
     TaxPayerRecord remove(String id);
 
     /**
      * Rozmiar bazy danych, czyli liczba rekordw
      *
      * @return liczba rekordw w bazie danych
      */
     int size();
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
public class TaxPayerBailoutDbImpl implements TaxPayerBailoutDB {
    private final Map<String,TaxPayerRecord> db;
 
    public TaxPayerBailoutDbImpl(int size) {
        db = new ConcurrentHashMap<String,TaxPayerRecord>(size);
    }
 
    @Override
    public TaxPayerRecord get(String id) {
        return db.get(id);
    }
 
    @Override
    public TaxPayerRecord add(String id, TaxPayerRecord record) {
        TaxPayerRecord old = db.put(id, record);
        if (old != null) {
            // przywraca stary TaxPayerRecord
            old = db.put(id, old);
        }
        return old;
    }
 
    @Override
    public TaxPayerRecord remove(String id) {
        return db.remove(id);
    }
 
    @Override
    public int size() {
        return db.size();
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
 
public class TaxCallable implements Callable<BailoutFuture> {
 
    private static long runTimeInMillis = BailoutMain.TEST_TIME;
    final private static ThreadLocal<Random> generator =
                                    BailoutMain.threadLocalRandom;
    private long nullCounter, recordsRemoved, newRecordsAdded;
    private int index;
    private String taxPayerId;
    final private List<String> taxPayerList;
    final private TaxPayerBailoutDB db;
 
    public TaxCallable(List<String> taxPayerList, TaxPayerBailoutDB db){
        this.taxPayerList = taxPayerList;
        this.db = db;
        index = 0;
    }
 
    @Override
    public BailoutFuture call() throws Exception {
        long iterations = 0L, elapsedTime = 0L;
        long startTime = System.currentTimeMillis();
        double iterationsPerSecond = 0;
        do {
            setTaxPayer();
            iterations++;
            TaxPayerRecord tpr = null;
            if (iterations == Long.MAX_VALUE) {
                long elapsed = System.currentTimeMillis() - startTime;
                iterationsPerSecond = iterations / 
                                          ((double) (elapsed / 1000));
                System.err.println("Przekroczenie licznika iteracji ...");
                System.err.println("Obliczanie liczby biecych operacji na sekund.");
                System.err.println("Liczba iteracji na sekund: " + 
                                   iterationsPerSecond);
                iterations = 0L;
                startTime = System.currentTimeMillis();
                runTimeInMillis -= elapsed;
            }
            if (iterations % 1001 == 0) {
                tpr = addNewTaxPayer(tpr);
            } else if (iterations % 60195 == 0) {
                tpr = removeTaxPayer(tpr);
            } else {
                tpr = updateTaxPayer(iterations, tpr);
            }
 
            if (iterations % 1000 == 0) {
                elapsedTime = System.currentTimeMillis() - startTime;
            }
        } while (elapsedTime < runTimeInMillis);
 
        if (iterations >= 1000) {
            iterationsPerSecond = iterations / 
                                  ((double) (elapsedTime / 1000));
        }
        BailoutFuture bailoutFuture =
                new BailoutFuture(iterationsPerSecond, newRecordsAdded,
                                  recordsRemoved, nullCounter);
        return bailoutFuture;
    }
 
    private TaxPayerRecord updateTaxPayer(long iterations,
                                          TaxPayerRecord tpr) {
        if (iterations % 1001 == 0) {
            tpr = db.get(taxPayerId);
        } else {
            // aktualizuje rekord podatnika w bazie danych
            tpr = db.get(taxPayerId);
            if (tpr != null) {
                long tax = generator.get().nextInt(10) + 15;
                tpr.taxPaid(tax);
            }
        }
        if (tpr == null) {
            nullCounter++;
        }
        return tpr;
    }
 
    private TaxPayerRecord removeTaxPayer(TaxPayerRecord tpr) {
        // usuwa podatnika z bazy danych
        tpr = db.remove(taxPayerId);
        if (tpr != null) {
            // usuwa rekord z TaxPayerList
            taxPayerList.remove(index);
            recordsRemoved++;
        }
        return tpr;
    }
 
    private TaxPayerRecord addNewTaxPayer(TaxPayerRecord tpr) {
        // dodaje nowego TaxPayer do bazy danych
        String tmpTaxPayerId = BailoutMain.getRandomTaxPayerId();
        tpr = BailoutMain.makeTaxPayerRecord();
        TaxPayerRecord old = db.add(tmpTaxPayerId, tpr);
        if (old == null) {
            // dodaje do listy (lokalnej)
            taxPayerList.add(tmpTaxPayerId);
            newRecordsAdded++;
        }
        return tpr;
    }
 
    public void setTaxPayer() {
        if (++index >= taxPayerList.size()) {
            index = 0;
        }
        this.taxPayerId = taxPayerList.get(index);
    }
}
--------------------------------------------------------------------------------------------------------------------------------------
public class BailoutFuture {
    private double iterationsPerSecond;
    private long recordsAdded, recordsRemoved, nullCounter;
 
    public BailoutFuture(double iterationsPerSecond, long recordsAdded,
                         long recordsRemoved, long nullCounter) {
        this.iterationsPerSecond = iterationsPerSecond;
        this.recordsAdded = recordsAdded;
        this.recordsRemoved = recordsRemoved;
        this.nullCounter = nullCounter;
    }
 
    public double getIterationsPerSecond() {
        return iterationsPerSecond;
    }
 
    public long getRecordsAdded() {
        return recordsAdded;
    }
 
    public long getRecordsRemoved() {
        return recordsRemoved;
    }
 
    public long getNullCounter() {
        return nullCounter;
    }
}






