Синхронизация потоков одного класса
В таком виде синхронизации нет. Под синхронизацией, в данном примере, подразумеваю, что сначала один поток выполняет метод implements, потом другой поток выполняет этот метод. Но если сделать переменную TS статической, или сделать статическим метод iteration, то синхронизация происходит. Почему не происходила синхронизация потоков без присвоения методу или переменной тип статической? P.S. Заранее извиняюсь за глупый вопрос. Просто для того, чтобы лучше вникнуть в пройденную тему, я подобным образом экспериментирую над кодом.
class TestSynch{
synchronized void iteration() {
int i=0;
for (; i <= 3_000; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
class ThreadClass implements Runnable{
Thread thread;
TestSynch TS = new TestSynch();
public ThreadClass (String name) {
thread = new Thread(this,name);
}
static ThreadClass createThread (String name) {
ThreadClass obj = new ThreadClass(name);
obj.thread.start();
return obj;
}
public void run() {
TS.iteration();
}
}
public class MainSeven {
public static void main(String[] args) throws InterruptedException {
ThreadClass myThr1 = ThreadClass.createThread("Поток №1");
ThreadClass myThr2 = ThreadClass.createThread("Поток №2");
myThr1.thread.join();
myThr2.thread.join();
System.out.println("Завершение основного потока");
}
}
На выходе:
...
Поток №2 472
Поток №1 525
Поток №1 526
Поток №2 473
Поток №2 474 и т.д. до 3000.
Если же сделать метод implements или переменную TS статическим:
static synchronized void iteration();
or
static TestSynch TS = new TestSynch();
То на выходе:
Поток №1 2996
Поток №1 2997
Поток №1 2998
Поток №1 2999
Поток №1 3000
Поток №2 0
Поток №2 1
Поток №2 2
Поток №2 3
Поток №2 4
Поток №2 5
Поток №2 6 и т.д
Ответы (1 шт):
Дело в том, что когда вы объявляете переменную как static то она создается на уровне класса (а не объекта), т.е. не важно сколько объектов класса вы создадите, эта переменная всегда будет одна.
То же самое происходит и с методом - если его объявить static, то этот метод будет объявлен на уровне класса, соответственно, если он синхронизирован, то синхронизация происходит по классу, а не по конкретному объекту (экземпляру этого класса).
Если простыми словами, то все объекты вашего класса вызывают один и тот же статический метод класса и, т.к. он объявлен как synchronized, то первый поток получает монитор объекта TestSynch.class и все остальные потоки ждут, пока монитор не освободится.
Аналог вашего кода с явным определением объекта, по которому проходит синхронизация будет выглядеть вот так:
class TestSynch {
static void iteration() {
synchronized (TestSynch.class) {
int i = 0;
for (; i <= 3_000; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
Если же вы уберете static с метода, то он станет методом экземпляра класса TestSynch, и, соответственно, синхронизация будет происходить на экземпляре класса (объекте класса). Таким образом, код будет уже таким:
class TestSynch {
void iteration() {
synchronized (this) {
int i = 0;
for (; i <= 3_000; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
Синхронизация, в таком случае будет работать только если несколько потоков пытаются вызвать этот метод параллельно на одном и том же экземпляре класса TestSynch, что у вас и происходит, когда вы объявляете переменную как static:
TestSynch TS = new TestSynch();
В этом случае, у вас создается одна переменная и каждый поток вызывает метод iteration этой переменной, т.е. он получает монитор этой переменной и остальные потоки ждут пока монитор освободится.