Следующий код демонстрирует, как синхронизировать определенные методы класса:
Скопируйте код кода следующим образом:
пакет мифрид;
общедоступный класс SyncThread расширяет поток
{
частная статическая строковая синхронизация = "";
частный метод StringType = "";
частный статический метод void (String s)
{
синхронизированный (синхронизированный)
{
синхронизация = с;
System.out.println(s);
пока (истина);
}
}
публичный недействительный метод1()
{
метод("Метод1");
}
общественный статический недействительный staticMethod1()
{
метод("статическийМетод1");
}
публичный недействительный запуск()
{
если (methodType.equals("статический"))
статическийМетод1();
иначе если (methodType.equals("нестатический"))
метод1();
}
общедоступный SyncThread (String MethodType)
{
this.methodType = MethodType;
}
public static void main(String[] args) выдает исключение
{
SyncThread sample1 = новый SyncThread("нестатический");
SyncThread sample2 = новый SyncThread("статический");
образец1.start();
образец2.start();
}
}
Результаты бега следующие:
Скопируйте код кода следующим образом:
метод1
статическийМетод1
Многие читатели могут быть удивлены, увидев приведенные выше результаты. В приведенном выше коде методы Method1 и staticMethod1 используют статическую строковую переменную sync для синхронизации. Одновременно может выполняться только один из этих двух методов, и оба метода будут выполнять оператор бесконечного цикла в строке 014. Таким образом, выходной результат может быть только одним из методов Method1 и staticMethod1. Но эта программа выводит обе строки.
Причина такого результата очень проста: мы узнаем ее, взглянув на строку 012. Оказывается, в этой строке меняется значение sync. Здесь я хочу поговорить о типе String в Java. Тип String отличается от других сложных типов в Java. При использовании переменной типа String, если вы один раз присвоите значение переменной, Java создаст новый экземпляр типа String. Как показано в следующем коде:
Скопируйте код кода следующим образом:
Строка s = "привет";
System.out.println(s.hashCode());
с = "мир";
System.out.println(s.hashCode());
в коде выше. Значения hashCode первого и переназначенного различны. Поскольку создание экземпляра класса String не требует использования new, при синхронизации переменной типа String будьте осторожны и не присваивайте значение этой переменной, иначе переменная не будет синхронизирована.
Поскольку в строке 012 был создан новый экземпляр для синхронизации, при условии, что метод1 выполняется первым, когда метод1 выполняет код в строке 013, значение синхронизации больше не является исходным значением, и метод1 по-прежнему блокирует переменную синхронизации. . В это время выполняется staticMethod1 для синхронизации(sync). Синхронизация, которая должна быть заблокирована в методе staticMethod1, и синхронизация, заблокированная методом Method1, больше не совпадают. Таким образом, синхронизация двух методов была нарушена.
Решением вышеуказанной проблемы, конечно же, является удаление строки 012. Эта строка добавлена в этот пример только для того, чтобы проиллюстрировать, что при использовании переменных класса для синхронизации методов, если значение переменной синхронизации изменяется в синхронизированном блоке, синхронизация между методами будет нарушена. Чтобы полностью избежать этой ситуации, вы можете использовать ключевое слово Final при определении переменных синхронизации. Например, строку 005 в приведенной выше программе можно изменить на следующий вид:
Скопируйте код кода следующим образом:
частная окончательная статическая строка синхронизации = "";
После использования ключевого слова Final синхронизация может присвоить ему значение только тогда, когда оно определено, и его нельзя изменить позже. Если sync присвоено значение в другом месте программы, программа не скомпилируется. В таких инструментах разработки, как Eclipse, подсказки будут выдаваться не в том месте.
Мы можем понимать синхронизированные блоки с двух точек зрения. Если понимать с точки зрения методов класса, соответствующие методы можно синхронизировать через переменные класса. Если вы понимаете это с точки зрения переменных класса, вы можете использовать синхронизированные блоки, чтобы гарантировать, что к переменной класса можно получить доступ только одним методом одновременно. Независимо от того, под каким углом вы это понимаете, суть их одна и та же: использовать переменные класса для получения блокировок синхронизации и добиваться синхронизации посредством взаимного исключения блокировок синхронизации.
Примечание. При использовании синхронизированных блоков следует помнить, что синхронизированные блоки могут использовать в качестве параметров только объекты. Если это переменная простого типа (например, int, char, boolean и т. д.), для синхронизации нельзя использовать синхронизированную переменную.