Pausa de protección de programación concurrente de Java en modo síncrono

Pausa protectora en modo sincronizado

Eso es suspensión protegida, que se usa en un hilo para esperar el resultado de la ejecución de otro hilo

Punto

  • Hay un resultado que debe pasarse de un hilo a otro, para que estén asociados con el mismo GuardedObject
  • Si hay resultados de un hilo a otro, puede usar colas de mensajes (ver productor / consumidor, modo asíncrono )
  • En el JDK, este modo se adopta para la realización de join y la realización de Future
  • Debido a que tenemos que esperar el resultado de la otra parte, se clasifica en modo síncrono.
    Inserte la descripción de la imagen aquí

Ejemplo 1, el hilo principal espera el resultado de la descarga del hilo secundario

Por ejemplo, el hilo principal espera el resultado de la descarga del hilo secundario.

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.List;

import static cn.itcast.pattern.Downloader.*;

@Slf4j(topic = "c.TestGuardedObject")
public class TestGuardedObject {
    
    
    public static void main(String[] args) {
    
    
        GuardedObject guardedObject = new GuardedObject();
        new Thread(() -> {
    
    
            try {
    
    
                List<String> response = download();
                log.debug("download complete...");
                guardedObject.complete(response);
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }).start();

        log.debug("waiting...");
        Object response = guardedObject.get();
        log.debug("get response: [{}] lines", ((List<String>) response).size());

    }


}

class GuardedObject {
    
    

    private Object response;
    private final Object lock = new Object();

    public Object get() {
    
    
        synchronized (lock) {
    
    
            // 条件不满足则等待
            while (response == null) {
    
    
                try {
    
    
                    lock.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            return response;
        }
    }

    public void complete(Object response) {
    
    
        synchronized (lock) {
    
    
            // 条件满足,通知等待线程
            this.response = response;
            lock.notifyAll();
        }
    }
}

Ejemplo 2, Esperando con tiempo de espera

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

import static cn.itcast.n2.util.Sleeper.sleep;

@Slf4j(topic = "c.TestGuardedObjectV2")
public class TestGuardedObjectV2 {
    
    
    public static void main(String[] args) {
    
    
        GuardedObjectV2 v2 = new GuardedObjectV2();
        new Thread(() -> {
    
    
            sleep(1);
            v2.complete(null);
            sleep(1);
            v2.complete(Arrays.asList("a", "b", "c"));
        }).start();

        Object response = v2.get(2500);
        if (response != null) {
    
    
            log.debug("get response: [{}] lines", ((List<String>) response).size());
        } else {
    
    
            log.debug("can't get response");
        }
    }
}


/**
 * 添加超时处理
 */
@Slf4j(topic = "c.GuardedObjectV2")
class GuardedObjectV2 {
    
    

    private Object response;
    private final Object lock = new Object();

    public Object get(long millis) {
    
    
        synchronized (lock) {
    
    
            // 1) 记录最初时间
            long last = System.currentTimeMillis();
            // 2) 已经经历的时间
            long timePassed = 0;
            while (response == null) {
    
    
                // 4) 假设 millis 是 1000,结果在 400 时唤醒了,那么还有 600 要等
                long waitTime = millis - timePassed;
                log.debug("waitTime: {}", waitTime);
                if (waitTime <= 0) {
    
    
                    log.debug("break...");
                    break;
                }
                try {
    
    
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                // 3) 如果提前被唤醒,这时已经经历的时间假设为 400
                timePassed = System.currentTimeMillis() - last;
                log.debug("timePassed: {}, object is null {}", timePassed, response == null);
            }
            return response;
        }
    }

    public void complete(Object response) {
    
    
        synchronized (lock) {
    
    
            // 条件满足,通知等待线程
            this.response = response;
            log.debug("notify...");
            lock.notifyAll();
        }
    }
}

El principio de unirse en JDK

En JDK, la realización de join y la realización de Future adoptan este modo

    public final synchronized void join(long millis)
    throws InterruptedException {
    
    
        long base = System.currentTimeMillis();//开始时间
        long now = 0;//经过的时间

        if (millis < 0) {
    
    
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
    
    //参数是0的话,就无限等待
            while (isAlive()) {
    
    //判断线程是否存活
                wait(0);
            }
        } else {
    
    
            while (isAlive()) {
    
    //判断线程是否存活
                long delay = millis - now;
                if (delay <= 0) {
    
    
                    break;
                }
                wait(delay);
                // base不变,currentTime不断增加,now变大
                now = System.currentTimeMillis() - base;
            }
        }
    }

Suspensión protectora extendida

En la imagen

  • Futures es como un buzón en el primer piso de un edificio residencial (cada buzón tiene un número de habitación),
  • T0, t2 y t4 a la izquierda son como residentes esperando correo,
  • T1, t3, t5 a la derecha son como cartero

Si necesita utilizar el objeto GuardedObject entre varias clases, no es muy conveniente pasarlo como parámetro, así que diseñe una clase intermedia para el desacoplamiento,
que no solo puede desacoplar [Result Waiter ] y [Result Producer], sino también al mismo tiempo. Apoyar la gestión de múltiples tareas.
Inserte la descripción de la imagen aquí
lograr

Clase de prueba

import lombok.extern.slf4j.Slf4j;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

@Slf4j(topic = "c.Test20")
public class Test20 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        for (int i = 0; i < 3; i++) {
    
    
            new People().start();
        }
        Sleeper.sleep(1);
        for (Integer id : Mailboxes.getIds()) {
    
    
            new Postman(id, "内容" + id).start();
        }
    }
}

Residentes y carteros que reciben correo

@Slf4j(topic = "c.People")
class People extends Thread{
    
    
    @Override
    public void run() {
    
    
        // 收信
        GuardedObject guardedObject = Mailboxes.createGuardedObject();
        log.debug("开始收信 id:{}", guardedObject.getId());
        Object mail = guardedObject.get(5000);
        log.debug("收到信 id:{}, 内容:{}", guardedObject.getId(), mail);
    }
}

@Slf4j(topic = "c.Postman")
class Postman extends Thread {
    
    
    private int id;
    private String mail;

    public Postman(int id, String mail) {
    
    
        this.id = id;
        this.mail = mail;
    }

    @Override
    public void run() {
    
    
        GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
        log.debug("送信 id:{}, 内容:{}", id, mail);
        guardedObject.complete(mail);
    }
}

buzón
Inserte la descripción de la imagen aquí

class Mailboxes {
    
    
    private static Map<Integer, GuardedObject> boxes = new Hashtable<>();

    private static int id = 1;
    // 产生唯一 id
    private static synchronized int generateId() {
    
    
        return id++;
    }

    public static GuardedObject getGuardedObject(int id) {
    
    
        return boxes.remove(id);
    }

    public static GuardedObject createGuardedObject() {
    
    
        GuardedObject go = new GuardedObject(generateId());
        boxes.put(go.getId(), go);
        return go;
    }

    public static Set<Integer> getIds() {
    
    
        return boxes.keySet();
    }
}

Objeto GuardedObject

// 增加超时效果
class GuardedObject {
    
    

    // 标识 Guarded Object
    private int id;

    public GuardedObject(int id) {
    
    
        this.id = id;
    }

    public int getId() {
    
    
        return id;
    }

    // 结果
    private Object response;

    // 获取结果
    // timeout 表示要等待多久 2000
    public Object get(long timeout) {
    
    
        synchronized (this) {
    
    
            // 开始时间 15:00:00
            long begin = System.currentTimeMillis();
            // 经历的时间
            long passedTime = 0;
            while (response == null) {
    
    
                // 这一轮循环应该等待的时间
                long waitTime = timeout - passedTime;//---这个参数防止虚假唤醒
                // 经历的时间超过了最大等待时间时,退出循环
                if (timeout - passedTime <= 0) {
    
    
                    break;
                }
                try {
    
    
                    this.wait(waitTime); // 虚假唤醒 15:00:01
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                // 求得经历时间
                passedTime = System.currentTimeMillis() - begin; // 15:00:02  1s
            }
            return response;
        }
    }

    // 产生结果
    public void complete(Object response) {
    
    
        synchronized (this) {
    
    
            // 给结果成员变量赋值
            this.response = response;
            this.notifyAll();
        }
    }
}

referencia

"Patrón de diseño Java multiproceso"

Supongo que te gusta

Origin blog.csdn.net/e891377/article/details/109152523
Recomendado
Clasificación