Synchronized — распространенный метод решения проблем параллелизма в языке Java, его еще ласково называют «встроенной блокировкой Java», что свидетельствует о его высоком статусе. Тем не менее, синхронизированный имеет множество применений.Когда он изменяет разные объекты, его значение также отличается.Давайте посмотрим на это вместе.
синхронизированное использование
синхронизированный можно использовать для измененияОбычные методы, статические методы и блоки кода.
① Модификация обычных методов
/**
* synchronized 修饰普通方法
*/
public synchronized void method() {
// .......
}
Когда synchronized изменяет общий метод, измененный метод называется синхронизированным методом, его областью действия является весь метод, а объектом действия является объект, вызывающий метод.
② Изменить статические методы
/**
* synchronized 修饰静态方法
*/
public static synchronized void staticMethod() {
// .......
}
Когда синхронизация изменяет статический метод, его областью действия является весь метод, а область действия — все объекты, вызывающие этот класс.
③ Изменить блок кода
Чтобы уменьшить степень детализации блокировки, мы можем использовать синхронизированный для оформления определенной части метода (блока кода), чтобы заблокировать часть кода в методе.Код реализации выглядит следующим образом:
public void classMethod() throws InterruptedException {
// 前置代码...
// 加锁代码
synchronized (SynchronizedExample.class) {
// ......
}
// 后置代码...
}
Когда приведенный выше код выполняется, измененный блок кода называется синхронизированным блоком операторов, а его областью действия является блок кода, заключенный в фигурные скобки "{}", а объектом действия является объект, вызывающий этот блок кода.
Но приведенный выше код, помимо блокировки класса, также может заблокировать это, конкретный пример выглядит следующим образом:
public void classMethod() throws InterruptedException {
// 前置处理代码...
synchronized (this) {
// ......
}
// 后置处理代码...
}
Вопрос в том, в чем разница между использованием synchronized для блокировки этого и класса? Разве они не блокируют один и тот же класс?
Ответ на самом деле нет, разница между блокировкой this и class все еще очень велика. Давайте посмотрим на разницу между ними на следующих 4 примерах.
1. Заблокированные классы совместно используют экземпляр класса
Во-первых, мы создаем 5 потоков и вызываем код класса синхронизированной блокировки для одного и того же объекта. Конкретный пример выглядит следующим образом:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建当前类实例
final SynchronizedExample example = new SynchronizedExample();
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 调用 synchronized 修饰的 class 方法
example.classMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 class 方法
* @throws InterruptedException
*/
public void classMethod() throws InterruptedException {
synchronized (SynchronizedExample.class) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
Результат выполнения вышеуказанной программы выглядит следующим образом:Из приведенных выше результатов видно, что пять потоков используют одну и ту же блокировку.
2. Блокировка класса для создания нескольких экземпляров
Далее мы создаем 5 потоков и вызываем код класса синхронизированной блокировки под разными объектами.Конкретный пример выглядит следующим образом:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 创建类实例
SynchronizedExample example = new SynchronizedExample();
// 调用 synchronized 修饰的 class 方法
example.classMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 class 方法
* @throws InterruptedException
*/
public void classMethod() throws InterruptedException {
synchronized (SynchronizedExample.class) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
Результат выполнения вышеуказанной программы выглядит следующим образом:Как видно из приведенных выше результатов, хотя это разные объекты, они все равно используют одну и ту же блокировку.
3. Заблокируйте это, чтобы поделиться экземпляром класса
Затем мы создаем 5 потоков и вызываем синхронизацию, чтобы заблокировать этот пример. Сначала наши пять потоков вызывают метод блокировки одного и того же объекта Пример кода выглядит следующим образом:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建当前类实例
final SynchronizedExample example = new SynchronizedExample();
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 调用 synchronized 修饰的 this 方法
example.thisMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 this 方法
* @throws InterruptedException
*/
public void thisMethod() throws InterruptedException {
synchronized (this) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
Результат выполнения вышеуказанной программы выглядит следующим образом:Из приведенных выше результатов видно, что все вышеперечисленные потоки используют одну и ту же блокировку.
4. Заблокируйте это, чтобы создать несколько экземпляров класса.
Последний пример является самым особенным. Мы используем synchronized, чтобы заблокировать его и позволить этим пяти потокам вызывать свои собственные методы создания объектов. Конкретные примеры приведены ниже:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 创建(多个)类实例
SynchronizedExample example = new SynchronizedExample();
// 调用 synchronized 修饰的 this 方法
example.thisMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 this 方法
* @throws InterruptedException
*/
public void thisMethod() throws InterruptedException {
synchronized (this) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
Результат выполнения вышеуказанной программы выглядит следующим образом:Из приведенных выше результатов видно, что при использовании synchronized для блокировки этого, если потоки вызывают не один и тот же объект, блокировки, используемые между этими потоками, являются их собственными независимыми блокировками.Этот результат полностью такой же, как результат синхронизированной блокировки класс разные.
Суммировать
Из приведенных выше 4 примеров мы можем сделать вывод, что когдаПри использовании синхронизированного класса блокировки независимо от того, используют ли они общий объект или создают несколько объектов, все они используют одну и ту же блокировку.,а такжеПри использовании синхронизированного для блокировки только один и тот же объект будет использовать одну и ту же блокировку, а блокировки между разными объектами будут разными..
Рекомендуемые статьи из этой серии
- Параллелизм. Урок 1. Сведения о потоке
- В чем разница между пользовательскими потоками и потоками демона в Java?
- Глубокое понимание пула потоков ThreadPool
- 7 способов создать пул потоков, настоятельно рекомендуется их использовать...
- Насколько хороша технология объединения? Я был потрясен, когда увидел сравнение между потоками и пулами потоков!
- Синхронизация потоков и блокировки в параллелизме
- Разница между volatile и синхронизированным
- Обязательно ли легкие замки быстрее, чем тяжелые замки?
- Приведет ли завершение потока таким образом к отключению службы?
- 5 решений для небезопасного потока SimpleDateFormat!
- ThreadLocal не прост в использовании? Ты бесполезен!
- Демонстрация кода переполнения памяти ThreadLocal и анализ причин!
- Признания Семафора: Я прав с ограничителем тока!
- CountDownLatch: Не сомневайтесь, подождите, пока все перегруппируются!
- CyclicBarrier: Когда все люди будут готовы, водитель может стартовать!
Подпишитесь на официальный аккаунт «Сообщество китайского языка Java», чтобы увидеть больше интересных и полезных статей о параллельных Java.