Если вам действительно нужна синхронизация остальной части конструктора с любыми потоками, которые так или иначе получают ссылку на ваш еще не полностью сконструированный объект, вы можете использовать синхронизированный блок:
public class Test {
public Test() {
final Test me = this;
synchronized(this) {
new Thread() {
@Override
public void run() {
// ... Reference 'me,' the object being constructed
synchronized(me) {
// do something dangerous with 'me'.
}
}
}.start();
// do something dangerous with this
}
}
}
Обычно считается плохим стилем «выдавать» ваш еще не построенный объект, как этот, поэтому синхронизированный конструктор не нужен.
В некоторых угловых случаях будет полезен синхронизированный конструктор.Вот более реалистичный пример из обсуждения ответа Божо:
public abstract class SuperClass {
public SuperClass() {
new Thread("evil") { public void run() {
doSomethingDangerous();
}}).start();
try {
Thread.sleep(5000);
}
catch(InterruptedException ex) { /* ignore */ }
}
public abstract void doSomethingDangerous();
}
public class SubClass extends SuperClass {
int number;
public SubClass () {
super();
number = 2;
}
public synchronized void doSomethingDangerous() {
if(number == 2) {
System.out.println("everything OK");
}
else {
System.out.println("we have a problem.");
}
}
}
Мы хотим, чтобы метод doSomethingDangerous()
вызывался только после завершения построения нашего объекта SubClass, например, мы хотим только "всеОК "вывод.Но в этом случае, когда вы можете редактировать только свой подкласс, у вас нет шансов достичь этого.Если бы конструктор мог быть синхронизирован, это решило бы проблему.
Итак, что мы узнаем об этом: никогда не делайте то, что я делал здесь, в конструкторе суперкласса, если ваш класс не является окончательным - и невызывайте любые не финальные методы вашего собственного класса из вашего конструктора.