Синхронизация с потоками.
1) НИКОГДА не используйте синхронизированный (это) в потоке, он не работает. Синхронизация с (this) использует текущий поток в качестве объекта блокировки потока. Поскольку каждый поток не зависит от других потоков, координация синхронизации отсутствует.
2) Тесты кода показывают, что в Java 1.6 на Mac не работает метод синхронизации.
3) synchronized (lockObj), где lockObj - это общий общий объект всех синхронизирующихся на нем потоков.
4) ReenterantLock.lock () и .unlock () работают. См. Руководства Java для этого.
Следующий код показывает эти пункты. Он также содержит потокобезопасный вектор, который будет заменен на ArrayList, чтобы показать, что многие потоки, добавляемые в вектор, не теряют никакой информации, в то время как то же самое с ArrayList может потерять информацию.
0) Текущий код показывает потерю информации из-за условий гонки
A) Прокомментируйте текущую помеченную строку A, и раскомментируйте строку A над ней, затем запустите, метод теряет данные, но не должен.
B) Обратный шаг A, раскомментируйте B и // конец блока}. Затем запустите, чтобы увидеть результаты без потери данных
C) Закомментируйте B, раскомментируйте C. Запустите, посмотрите, как происходит синхронизация (это) потери данных, как и ожидалось.
Не успеваю завершить все варианты, надеюсь, это поможет.
Если выполняется синхронизация по (этому) или метод синхронизации работает, укажите, какую версию Java и ОС вы тестировали. Спасибо.
import java.util.*;
/** RaceCondition - Shows that when multiple threads compete for resources
thread one may grab the resource expecting to update a particular
area but is removed from the CPU before finishing. Thread one still
points to that resource. Then thread two grabs that resource and
completes the update. Then thread one gets to complete the update,
which over writes thread two's work.
DEMO: 1) Run as is - see missing counts from race condition, Run severa times, values change
2) Uncomment "synchronized(countLock){ }" - see counts work
Synchronized creates a lock on that block of code, no other threads can
execute code within a block that another thread has a lock.
3) Comment ArrayList, unComment Vector - See no loss in collection
Vectors work like ArrayList, but Vectors are "Thread Safe"
May use this code as long as attribution to the author remains intact.
/mf
*/
public class RaceCondition {
private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
// private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)
private String countLock="lock"; // Object use for locking the raceCount
private int raceCount = 0; // simple add 1 to this counter
private int MAX = 10000; // Do this 10,000 times
private int NUM_THREADS = 100; // Create 100 threads
public static void main(String [] args) {
new RaceCondition();
}
public RaceCondition() {
ArrayList<Thread> arT = new ArrayList<Thread>();
// Create thread objects, add them to an array list
for( int i=0; i<NUM_THREADS; i++){
Thread rt = new RaceThread( ); // i );
arT.add( rt );
}
// Start all object at once.
for( Thread rt : arT ){
rt.start();
}
// Wait for all threads to finish before we can print totals created by threads
for( int i=0; i<NUM_THREADS; i++){
try { arT.get(i).join(); }
catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
}
// All threads finished, print the summary information.
// (Try to print this informaiton without the join loop above)
System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
MAX*NUM_THREADS, raceList.size(), raceCount );
System.out.printf("Array lost %,d. Count lost %,d\n",
MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
} // end RaceCondition constructor
class RaceThread extends Thread {
public void run() {
for ( int i=0; i<MAX; i++){
try {
update( i );
} // These catches show when one thread steps on another's values
catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
catch( OutOfMemoryError oome ) { System.out.print("O"); }
}
}
// so we don't lose counts, need to synchronize on some object, not primitive
// Created "countLock" to show how this can work.
// Comment out the synchronized and ending {, see that we lose counts.
// public synchronized void update(int i){ // use A
public void update(int i){ // remove this when adding A
// synchronized(countLock){ // or B
// synchronized(this){ // or C
raceCount = raceCount + 1;
raceList.add( i ); // use Vector
// } // end block for B or C
} // end update
} // end RaceThread inner class
} // end RaceCondition outter class