Это 29-й день моего участия в Gengwen Challenge.Подробности о мероприятии:Обновить вызов
Статьи по Теме
Резюме многопоточности Java:Многопоточность Java
предисловие
В предыдущей статье было представлено явление ошибок данных в случае параллелизма.
- Параллелизм: один и тот же объект управляется несколькими потоками одновременно, то есть разные потоки одновременно работают с одним и тем же адресом ресурса, что приводит к беспорядку данных.
- Синхронизация: несколько потоков, которым необходимо получить доступ к ресурсам одновременно, входят в пул ожидания объекта и ждут, пока предыдущий поток завершит его использование.
- Блокировка: Каждый объект имеет блокировку.Когда объект получен, он монополизирует ресурс, и другие потоки должны ждать и освобождать его после окончания использования.
- Поток, удерживающий блокировку, приводит к зависанию всех других потоков, которым требуется блокировка.
- В условиях многопоточной конкуренции блокировка и снятие блокировки вызовет больше переключений контекста и задержек планирования, вызывая проблемы с производительностью.
- Если поток с высоким приоритетом ждет, пока поток с низким приоритетом освободит блокировку, это вызовет инверсию приоритета и вызовет проблемы с производительностью.
1. Метод синхронизации
Сначала позвольте мне представитьsynchronizedключевые слова.
public synchronized void method(int args){}
-
синхронизировано:
- Блокировка по умолчанию является собственным объектом.
- Для охвата объектов обычно используется синхронизированный блок.
- То есть объект, в котором заблокирован общий ресурс.
-
Пример кода:
/**
* 手机抢购案例
*/
public class PhoneSnapUp implements Runnable {
private Integer inventory = 10;//手机库存
private boolean flag = true;
public static void main(String[] args) {
PhoneSnapUp phoneSnapUp = new PhoneSnapUp();
//模拟5人同时抢购,即同时开启5个线程
new Thread(phoneSnapUp, "丁大大1号").start();
new Thread(phoneSnapUp, "丁大大2号").start();
new Thread(phoneSnapUp, "丁大大3号").start();
new Thread(phoneSnapUp, "丁大大4号").start();
new Thread(phoneSnapUp, "丁大大5号").start();
}
@Override
public synchronized void run() {
while (flag){
try {
// synchronized (this) {
buy();
// }
} catch (Exception e) {
e.printStackTrace();
}
}
}
//购票方法提出来
private void buy() throws Exception {
//当库存为0时,抢购结束
if (inventory <= 0) {
flag = false;
return;
}
//模拟延迟,否则结果不容易看出来
Thread.sleep(500);
//每次抢购完,库存减1
System.out.println("恭喜!!" + Thread.currentThread().getName() + "--抢到了一台小米12!库存还剩:" + --inventory + "台");
}
}
- Результат выполнения следующий:
- Резюме: Метод синхронизации может быть использован для того, чтобы результат не был ошибочным.
- Но поскольку это метод, добавление всего содержимого синхронизированного метода эквивалентно блокировке, что может вызвать проблемы с эффективностью и привести к блокировке программы~
- Поэтому мы обычно используем синхронизированные блоки кода для реализации операций блокировки.
2. Блок синхронизированного кода
synchronized(Obj){}
- Случай кода: остальные коды совпадают с методом синхронизации, они не повторяются и не вставляются.Здесь вводится только код метода запуска.
@Override
public void run() {
while (flag){
try {
synchronized (this) {
buy();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Результаты:
-
Суммировать:
-
Результаты согласуются с методом синхронизации, доказывая, что оба метода могут гарантировать точность результатов.
-
Блоки синхронизированного кода предназначены для блокировки фиксированных вещей, и на другое содержимое метода это не влияет.
-
Чтобы привести грубый пример, если вы идете в дерьмо, метод синхронизации эквивалентен прямому запиранию двери туалета, вы используете только одну из трех ям, что является типичной тратой ресурсов. В блоке синхронного кода, в какую бы яму вы ни вошли, дверь ямы будет заперта, и другие люди смогут нормально пользоваться другими ямами, ха-ха~
-
-
будь осторожен:
- Obj может быть любым объектом, но в качестве монитора синхронизации рекомендуется использовать общий ресурс.
- Нет необходимости указывать монитор синхронизации в методе синхронизации, потому что монитор синхронизации метода синхронизации это то, что является самим объектом или классом
-
Процесс выполнения: Процесс выполнения монитора синхронизации:
- Первый поток обращается к монитору синхронизации, блокирует его и выполняет код в нем.
- Второй поток получает доступ и обнаруживает, что монитор синхронизации заблокирован и недоступен.
- После завершения доступа к первому потоку монитор синхронизации разблокируется.
- Второй поток обращается, обнаруживает, что монитор синхронизации не имеет блокировки, затем блокируется и обращается
3. Тупик
это было сказано вышеЗамок, то если два потока одновременно получают общий ресурс и не могут его освободить, это вызоветявление тупика.
-
Простое и грубое понимание:
- Два ресурса A и B
- Дин И удерживает блокировку ресурса A и хочет продолжить блокировку ресурса B после выполнения
- Дин Эр удерживает блокировку ресурса B и хочет продолжить блокировку ресурса A после выполнения
- Если ни один из них не закончит выполнение, то есть они не снимут блокировку друг с друга, они будут сражаться, и ни один из них не сможет выполнить.
- привести в тупик
-
Текст всегда непонятен, и его точно можно понять, если следовать коду:
/**
* 模拟多线程死锁的情况
*/
public class Demo {
public static void main(String[] args) {
DeadLockThread deadLockThread = new DeadLockThread();
new Thread(deadLockThread,"丁一+").start();
new Thread(deadLockThread,"丁二+").start();
}
}
class DeadLockThread implements Runnable {
A a = new A();
B b = new B();
@SneakyThrows
@Override
public void run() {
if (Thread.currentThread().getName().equals("丁一")){
synchronized (this){
System.out.println(Thread.currentThread().getName());
a.soutA();
Thread.sleep(2000);
b.soutB();
}
}else {
synchronized (this) {
System.out.println(Thread.currentThread().getName());
b.soutB();
Thread.sleep(2000);
a.soutA();
}
}
}
}
class A {
public void soutA(){
System.out.println("我是A");
}
}
class B {
public void soutB(){
System.out.println("我是B");
}
}
- Результат выполнения следующий:
-
Резюме: Четыре необходимых условия взаимоблокировки:
- Условие взаимного исключения: ресурс может использоваться только одним процессом одновременно.
- Условия запроса и удержания: когда процесс блокируется запросом ресурсов, он будет удерживать полученные ресурсы.
- Условие отсутствия лишения: ресурсы, полученные процессом, не могут быть принудительно лишены до окончания использования.
- Условие циклического ожидания: между несколькими процессами формируется прямое циклическое отношение ресурса ожидания.
-
Просто сломайте любой из них, чтобы избежать взаимоблокировки
4. Блокировка замка
-
Синхронизация путем явного определения объекта блокировки синхронизации (Lock)
-
Класс ReentrantLock реализует интерфейс Lock, который имеет ту же семантику параллелизма и памяти, что и синхронизированный.В управлении потокобезопасностью чаще используется ReentrantLock, который может явно блокировать и снимать блокировки.
-
Случай кода:
/**
* 使用Lock锁
*/
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock = new TestLock2();
new Thread(testLock, "A").start();
new Thread(testLock, "B").start();
new Thread(testLock, "C").start();
}
}
class TestLock2 implements Runnable{
int count = 1000;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while(true)
{
try {
//进入加锁状态
lock.lock();
if(count > 0)
System.out.println(Thread.currentThread().getName() + "---" +count--);
else
break;
}
finally {
//解锁
lock.unlock();
}
}
}
}
- Результаты:
- Суммировать:
- В случае отсутствия блокировки ABC может одновременно выполнять подсчет, что приводит к беспорядку данных.
- После добавления блокировки ABC ставит операцию в очередь
Впереди долгий путь, и я обязательно буду его искать вдоль и поперёк~
Если вы думаете, что я блогеры хорошо пишу! Писать нелегко, пожалуйста, ставьте лайки, подписывайтесь и комментируйте, чтобы поощрять блоггеров ~ хахах