Java concurrencia bloquear de forma explícita

explícitamente bloquea 

¿Por qué incluso tener un bloqueo sincronizado? programa Java se realiza mediante la función de bloqueo de palabras clave sincronizada, utilice la palabra clave sincronizada adquirirá implícitamente una cerradura, pero se bloqueará la adquisición y liberación de cura, y que es conseguir re-lanzado.

Monitor sincronizada combinación de palabras clave de objeto, la JVM proporciona una semántica "integrado Lock" para nosotros, este bloqueo es muy simple, no es necesario que preocuparse por el proceso de desbloqueo y de bloqueo, sólo tenemos que decir qué código de máquina virtual bloque necesidad de bloqueo, otros detalles se realizará por el compilador y la propia máquina virtual.

Nuestro "construido-Lock" se puede entender como un sistema incorporado en características de la JVM, no es compatible con algunas características avanzadas de personalización, por ejemplo, quiero fomentar la competencia leal en la cerradura, quiero en base a diferentes criterios a hilo bloqueado en una cola diferente, quiero apoyar regulares de tiempo de espera de bloqueo de la competencia de retorno, también quiero hilo bloqueado puede interrumpir peticiones y así sucesivamente.

Estas necesidades especiales son "construidos-Lock" no se pueden cumplir, por lo que los niveles de JDK y la introducción del concepto de "bloqueo explícito" ya no es responsable de la JVM para bloquear y liberar el bloqueo, la liberación de estas dos acciones nos dan un programa para hacer nivel de programa está poco complicado inevitable una, pero están bloqueados mayor flexibilidad, y puede soportar más características de personalización, pero requiere que usted tenga una comprensión más profunda de la cerradura.

Bloqueo de uso estándar

Por último bloque bloqueo se libera, después de que el objeto es asegurar que el bloqueo se adquiere, se puede finalmente liberado. No se encierre en el proceso de escribir el bloque try, como si la adquisición se produjo en el momento de la cerradura (cerradura implementaciones personalizadas) anomalía, se produce una excepción, sino que también daría lugar a la liberación de la cerradura por ninguna razón.

Lock API común

nota:

No hay requisitos especiales (de espera de bloqueo de roscas a tomar descanso), se recomienda el uso de sincronizado de palabras clave a partir del consumo de recursos se refiere, Lock es una memoria clase que consume, sincronizado de palabras clave es un primer plano de un programa sin un nuevo objetivo, el consumo relativo de recursos pequeña.

ReentrantLock bloqueo de reentrada (clase de implementación de bloqueo)

reentrada bloqueo

En pocas palabras: "El haber sido el mismo hilo para bloquear varias veces siguen aplicando al derecho a usar el bloqueo." El apoyo implícito vuelva a introducir la palabra clave sincronizada, tal como una modificación sincronizada del método recursivo, cuando el método de ejecución, hilos de ejecución todavía varias veces para obtener el bloqueo después de adquirir la cerradura. ReentrantLock al llamar método de bloqueo (), ha sido adquirida para bloquear el hilo puede llamar a la cerradura de nuevo () para obtener el bloqueo sin bloquear

Justa y bloqueo injusto

Si en el tiempo, la primera solicitud para obtener bloqueos primero debe cumplirse, entonces el bloqueo es justo, por el contrario, no es justo. El acceso equitativo a la cerradura, que es el que más tiempo esperando hilo de mayor prioridad para adquirir la cerradura, se puede decir adquisición de bloqueo es secuencial. ReentrantLock proporciona un constructor, para controlar si el bloqueo es justo. De hecho, el mecanismo de bloqueo es a menudo no es justo alta eficiencia injusta. Una de las razones en el caso de la altamente competitiva, justa y rendimiento sin bloqueo de una cerradura justa del desempeño es: hay retrasos significativos en la recuperación entre un hilo suspendido en realidad comenzó a correr con el hilo. Un hilo Supongamos que mantiene un bloqueo, la solicitud de bloqueo y el hilo B. Desde esta cerradura se ha celebrado por el hilo A, por lo que será suspendido B. Cuando se libera el bloqueo A, B será despertado, por lo que los intentos de obtener el bloqueo de nuevo. Al mismo tiempo, si C también solicitar la cerradura, entonces C es probable que se obtenga antes de B está totalmente despierto, uso y liberar el bloqueo. Tal situación es una situación de "ganar-ganar": B Tiempo de adquirir un bloqueo y no posponer C cerradura, adquiridos anteriormente, y mejorar el rendimiento también ganado.

Nota: del método de bloqueo de feria no predeterminado ReentrantLock puede ser proporcionado por la construcción de ReentrantLock justo cerradura, justo para el bloqueo no sincronizada, el rendimiento de bloqueo que no justo justo alta de bloqueo y de ReentrantLock también sincronizado llamado bloqueo exclusivo

código demuestra ReentrantLock

/**
 * 类说明:使用Lock的范例
 */
public class LockCase {
    private Lock lock = new ReentrantLock();
    private int age = 100000;//初始100000

    private static class TestThread extends Thread {

        private LockCase lockCase;

        public TestThread(LockCase lockCase, String name) {
            super(name);
            this.lockCase = lockCase;
        }

        @Override
        public void run() {
            for (int i = 0; i < 100000; i++) {//递增100000
                lockCase.test();
            }
            System.out.println(Thread.currentThread().getName()
                    + " age =  " + lockCase.getAge());
        }
    }

    public void test() {
        lock.lock();
        try {
            age++;
        } finally {
            lock.unlock();
        }
    }

    public void test2() {
        lock.lock();
        try {
            age--;
        } finally {
            lock.unlock();
        }
    }

    public int getAge() {
        return age;
    }


    public static void main(String[] args) throws InterruptedException {
        LockCase lockCase = new LockCase();
        Thread endThread = new TestThread(lockCase, "endThread");
        endThread.start();
        for (int i = 0; i < 100000; i++) {//递减100000
            lockCase.test2();
        }
        System.out.println(Thread.currentThread().getName()
                + " age =  " + lockCase.getAge());

    }
}

Lectura y escritura de bloqueo ReentrantReadWriteLock

La cerradura básica se ha mencionado anteriormente (como objeto mutex y ReentrantLock) son bloqueo exclusivo, que bloquea al mismo tiempo que permite sólo un hilo de acceso, bloqueos de lectura-escritura, mientras que al mismo tiempo permite que varios subprocesos para el acceso de lectura, pero hilo acceso de escritura, todas las roscas leen y escriben otros hilos se bloquean. Lectura y escritura de bloqueo mantiene un bloqueo, un bloqueo y un bloqueo de lectura-escritura, lectura y mediante la separación de bloqueos de escritura, por lo que la concurrencia en comparación con el bloqueo exclusivo en general se ha mejorado en gran medida. 

Además de la parte exterior operación de escritura garantizada de la elevación simultánea de la visibilidad de la operación de lectura, lectura-escritura cerraduras se pueden simplificar escena interactúan mediante programación leer. Considere la definición de una estructura de datos de memoria caché compartida utilizada en el programa, que proporciona la mayor parte de los servicios de lectura de tiempo (como la consulta y la búsqueda), y la operación de escritura ocupa muy poco tiempo, pero actualizado después de la operación de escritura para completar la necesidad de un servicio de lectura de seguimiento visibles. 

En la ausencia de apoyo bloqueos de lectura y escritura (antes Java5), si es necesario para completar el trabajo necesario para utilizar Java esperando mecanismo de notificación, cuando se inicia una operación de escritura más tarde de todas las operaciones de escritura se lee en un estado de espera, única escritura después de la operación se ha completado y notifica a todos de espera para operaciones de lectura para continuar (a depender de la sincronización clave sincronizado entre la operación de escritura), el objetivo es hacer que la lectura capaz de leer los datos correctos no aparece lectura sucia. interruptor de bloqueo de escritura para lograr las funciones anteriores, sólo tendrá que adquirir un bloqueo de lectura en una lectura, bloqueo de escritura para conseguir una operación de escritura. Cuando se adquiere un bloqueo de escritura, el seguimiento (no corriente hilo de escritura) operaciones de lectura y escritura están bloqueados, después de que el bloqueo de escritura se libera, todas las operaciones continúan, la ejecución programática en relación con el uso de esperar mecanismo de notificación se refiere, se convierte simple y llanamente. 

En general, el rendimiento de bloqueo de escritura se bloqueará de forma exclusiva, porque la mayoría de las escenas se leen de escritura. cerraduras en el caso de una lectura de escritura, lectura y escritura se pueden proporcionar mejor que la concurrencia bloqueo exclusivo y el rendimiento 

ReentrantReadWriteLock alcanzar realmente es  ReadWriteLock  Interfaz

ADO en el código

Lea y bloqueo de escritura lógica

/**
 * 类说明:  读写锁
 */
public class UseRwLock  implements GoodsService{

    private GoodsInfo goodsInfo;

    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock getLock = lock.readLock();//读锁
    private final Lock setLock = lock.writeLock();//写锁

    public UseRwLock(GoodsInfo goodsInfo) {
        this.goodsInfo = goodsInfo;
    }

    @Override
    public GoodsInfo getNum() {
        //获取读锁
        getLock.lock();
        try{
            SleepTools.ms(5);
            //TODO 我们平时的查询接口
            return this.goodsInfo;
        }finally {
            getLock.unlock();
        }
    }

    @Override
    public void setNum(int number) {
        //获取写锁
        setLock.lock();
        try{
            SleepTools.ms(5);
            //TODO 我们平时的添加接口
            goodsInfo.changeNumber(number);
        }finally {
            setLock.unlock();
        }
    }
}

llamada 

/**
 *类说明:对商品进行业务的应用
 */
public class BusiApp {
    static final int readWriteRatio = 10;//读写线程的比例
    static final int minthreadCount = 3;//最少线程数
    //读操作
    private static class GetThread implements Runnable{

        private GoodsService goodsService;
        public GetThread(GoodsService goodsService) {
            this.goodsService = goodsService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            for(int i=0;i<100;i++){//操作100次
                goodsService.getNum();
            }
            System.out.println(Thread.currentThread().getName()+"读取商品数据耗时:"
             +(System.currentTimeMillis()-start)+"ms");

        }
    }

    //写操做
    private static class SetThread implements Runnable{

        private GoodsService goodsService;
        public SetThread(GoodsService goodsService) {
            this.goodsService = goodsService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            Random r = new Random();
            for(int i=0;i<10;i++){//操作10次
            	SleepTools.ms(50);
                goodsService.setNum(r.nextInt(10));
            }
            System.out.println(Thread.currentThread().getName()
            		+"写商品数据耗时:"+(System.currentTimeMillis()-start)+"ms---------");

        }
    }

    public static void main(String[] args) throws InterruptedException {
        GoodsInfo goodsInfo = new GoodsInfo("Cup",100000,10000);
        GoodsService goodsService = new UseRwLock(goodsInfo);
        for(int i = 0;i<minthreadCount;i++){
            Thread setT = new Thread(new SetThread(goodsService));
            for(int j=0;j<readWriteRatio;j++) {
                Thread getT = new Thread(new GetThread(goodsService));
                getT.start();           	
            }
            SleepTools.ms(100);
            setT.start();
        }
    }
}

Interfaz condición

Condición método común

Condición de los paradigmas de uso

condición de uso

Paradigma y wait (), notify () espera a que la notificación de similares

/**
 *类说明:Condition等待通知演示
 */
public class ExpressCond {
    public final static String CITY = "ShangHai";
    private int km;/*快递运输里程数*/
    private String site;/*快递到达地点*/
    private Lock kmLock = new ReentrantLock();
    private Lock siteLock = new ReentrantLock();
    private Condition kmCond = kmLock.newCondition();
    private Condition siteCond = siteLock.newCondition();

    public ExpressCond() {
    }

    public ExpressCond(int km, String site) {
        this.km = km;
        this.site = site;
    }

    /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
    public void changeKm(){
        kmLock.lock();
        try{
            this.km = 101;
            kmCond.signal();
            //kmCond.signalAll();
        }finally {
            kmLock.unlock();
        }
        
        
    }

    /* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
    public  void changeSite(){
    	siteLock.lock();
    	try {
    		this.site = "BeiJing";
    		siteCond.signal();//通知其他在锁上等待的线程
    	}finally {
    		siteLock.unlock();
    	}
    }

    /*当快递的里程数大于100时更新数据库*/
    public void waitKm(){
        kmLock.lock();
        try{
            while(this.km<100){
                try {
                    kmCond.await();
                    System.out.println("Check Site thread["
                            +Thread.currentThread().getId()
                            +"] is be notified");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }finally {
            kmLock.unlock();
        }


        System.out.println("the Km is "+this.km+",I will change db");
    }

    /*当快递到达目的地时通知用户*/
    public void waitSite(){
    	siteLock.lock();
    	try {
        	while(this.site.equals(CITY)) {
        		try {
    				siteCond.await();//当前线程进行等待
    				System.out.println("check Site thread["+Thread.currentThread().getName()
    						+"] is be notify");
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
        	}
    	}finally {
    		siteLock.unlock();
    	}

        System.out.println("the site is "+this.site+",I will call user");
    }
}
/**
 *类说明:单锁的实现 等待通知
 */
public class ExpressCondOneLock {
    public final static String CITY = "ShangHai";
    private int km;/*快递运输里程数*/
    private String site;/*快递到达地点*/
    private Lock lock = new ReentrantLock();
    private Condition kmCond = lock.newCondition();
    private Condition siteCond = lock.newCondition();

    public ExpressCondOneLock() {
    }

    public ExpressCondOneLock(int km, String site) {
        this.km = km;
        this.site = site;
    }

    /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
    public void changeKm(){
		lock.lock();
    	try {
    		this.km = 101;
    		kmCond.signal();//通知其他在锁上等待的线程
    	}finally {
			lock.unlock();
    	}
        
        
    }

    /* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
    public  void changeSite(){
		lock.lock();
    	try {
    		this.site = "BeiJing";
    		siteCond.signal();//通知其他在锁上等待的线程
    	}finally {
			lock.unlock();
    	}    	
    }

    /*当快递的里程数大于100时更新数据库*/
    public void waitKm(){
		lock.lock();
    	try {
        	while(this.km<100) {
        		try {
        			kmCond.await();//当前线程进行等待
    				System.out.println("check km thread["+Thread.currentThread().getName()
    						+"] is be notify");
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
        	}    		
    	}finally {
			lock.unlock();
    	}

        System.out.println("the Km is "+this.km+",I will change db");
    }

    /*当快递到达目的地时通知用户*/
    public void waitSite(){
		lock.lock();
    	try {
        	while(this.site.equals(CITY)) {
        		try {
    				siteCond.await();//当前线程进行等待
    				System.out.println("check Site thread["+Thread.currentThread().getName()
    						+"] is be notify");
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}   		
        	}
    	}finally {
			lock.unlock();
    	}      	

        System.out.println("the site is "+this.site+",I will call user");
    }
}

Por último, como una clase de prueba

/**
 * 类说明:测试Lock和Condition实现等待通知
 */
public class TestCond {
    private static ExpressCond express = new ExpressCond(0, ExpressCond.CITY);

    /*检查里程数变化的线程,不满足条件,线程一直等待*/
    private static class CheckKm extends Thread {
        @Override
        public void run() {
            express.waitKm();
        }
    }

    /*检查地点变化的线程,不满足条件,线程一直等待*/
    private static class CheckSite extends Thread {
        @Override
        public void run() {
            express.waitSite();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new CheckSite().start();
        }
        for (int i = 0; i < 3; i++) {
            new CheckKm().start();
        }

        Thread.sleep(1000);
        express.changeKm();//快递里程变化
    }
}

 

 

 

Publicado 18 artículos originales · ganado elogios 4 · Vistas 145

Supongo que te gusta

Origin blog.csdn.net/weixin_42081445/article/details/105000279
Recomendado
Clasificación