同步锁之lock

一、 synchronized的缺陷

当一个代码块被synchronized修饰时,同时该代码块被一个线程执行,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

1)获取锁的线程执行完成代码块,自动释放锁资源

2)代码块中执行异常,由jvm释放锁资源

如果在执行代码块时候,一个线程在代码块执行过程中Thread.sleep() 睡眠  线程被阻塞了,其他线程只能等待当前线程执行完成后才能执行。及其浪费效率。

另外当多个线程在执行写与写操作时,会发生线程冲突,但当多个线程用于读操作,其中一个线程读取占用的锁资源  而其他线程只能等待造成浪费资源。

通过多个线程读取操作线程不会冲突,通过lock可以实现。

不同点:

synchronized是java内置的,是java关键字,lock 是一个接口  不是内置的通过这个接口可以实现同步访问

synchronized不需要用户手动释放锁资源,当同步方法或者同步代码块执行完成后,系统会自动让线程释放锁资源。而Lock必须要手动释放锁资源,如果不释放会出现死锁

二、 java.util.concurrent.locks包下常用的类

 1) Lock 是一个接口

提供了六个方法

void lock();    boolean tryLock(); boolean tryLock(long time,timeUnit unit); void  lockInteruptibly(); contition newContition()  void unlock();

其中lock()  tryLock()   tryLock(long time,timeUnit unit)  lockInteruptibly() 用于获取锁    unlock() 用于释放锁

由于采用lock  不会自动释放锁,需要手动释放锁  所以采用lock 必须在try{}catch(){}finally{}异常捕获中进行,在finally中释放锁

lock()是最常用的获取锁的方式

例子:

Lock lock = ..

lock.lock();

try{

   }catch(Exception e){

}finally{

    lock.unlock()

  }

tryLock 尝试获取锁,如果获取到返回true 如果获取不到返回false   不会拿不到锁一致在等待

tryLock(long time,TimeUnit unit) 与tryLock()一样都是尝试获取锁,如果获取到返回true  否则返回false  区别在于tryLock(long time ,TimeUnit unit)会等待一定时间,如果直接获取到锁返回true 或者在设置的等待时间内获取到锁返回true  否则返回flase

Lock lock = ..

if(lock.tryLock()){

  try{

  }catch(){

}finally{

   lock.unlock(); 

}

 }

lockInterruptibly() 可以用来获取锁,但是如果在获取的锁已经被其他线程锁占用  在等待过程中可以中断当前线程的等待状态。通俗的将  如果 a  b两个线程通过Lock.lockInterruptibly()获取某一个锁时,如果a先获取到了锁   b处于等待状态 那么b可以调用b.interrup()方法中断b的等待状态

由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try块中或者在调用lockInterruptibly()的方法外声明抛出InterruptedException。

public void method () throws InterruptedException{

  lock.Interruptibly();

try{

  }catch(){

}finally{

  lock.unlock();

}

 }

当一个线程获取到了锁 是不会被interrup()方法中断  只有处于等待状态的线程在才能被中断。

2)ReadWriteLock  可重入锁

ReadWriteLock是Lock接口的唯一实现类

Lock 接口的实现方式:

package cn.ac.bcc.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {

    private List<Integer> list = new ArrayList<>();

    public static void main(String[] args) {

        //实例化当前类对象
        final LockDemo ld = new LockDemo();
        //创建两个线程对象  调用insert方法
         new Thread(new Runnable(){
            @Override
            public void run() {

              ld.insert(Thread.currentThread());

            }

        }).start();

         new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                ld.insert(Thread.currentThread());
            }

         }).start();
    }

    public void insert(Thread thread){

        //创建局部lock锁对象
        Lock lock = new ReentrantLock();
        System.out.println(lock);
        //获取锁
        lock.lock();
        try {
            for(int i=0;i<5;i++){
                list.add(i);
            }
            System.out.println(Thread.currentThread().getName()+"获取了锁");
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            //释放锁
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+"释放了锁");
        }
    }

}

运行结果:

[email protected][Unlocked]
[email protected][Unlocked]
Thread-0获取了锁
Thread-1获取了锁
Thread-0释放了锁
Thread-1释放了锁

产生这种结果的原因: 当多个线程获取同一个对象的方法中的局部变量,每一个线程都会获取一个局部变量lock的副本   通过打印锁对象地址可以发现当前锁对象是不同的锁 所以他们可以获取不同的锁

解决这种方案:

将获取锁对象成员变量  属于当前对象

package cn.ac.bcc.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {

    private List<Integer> list = new ArrayList<>();
    //创建局部lock锁对象
    private Lock lock = new ReentrantLock();

    public static void main(String[] args) {

        //实例化当前类对象
        final LockDemo ld = new LockDemo();
        //创建两个线程对象  调用insert方法
         new Thread(new Runnable(){
            @Override
            public void run() {

              ld.insert(Thread.currentThread());

            }

        }).start();

         new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                ld.insert(Thread.currentThread());
            }

         }).start();
    }

    public void insert(Thread thread){

        System.out.println(lock);
        //获取锁
        lock.lock();
        try {
            for(int i=0;i<5;i++){
                list.add(i);
            }
            System.out.println(Thread.currentThread().getName()+"获取了锁");
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            //释放锁
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+"释放了锁");
        }
    }

}

运行结果:

[email protected][Unlocked]
[email protected][Locked by thread Thread-0]
Thread-0获取了锁
Thread-0释放了锁
Thread-1获取了锁
Thread-1释放了锁

tryLock()

package cn.ac.bcc.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {

    private List<Integer> list = new ArrayList<>();
    //创建局部lock锁对象
    private Lock lock = new ReentrantLock();

    public static void main(String[] args) {

         //实例化当前类对象
         final LockDemo ld = new LockDemo();
        //创建两个线程对象  调用insert方法
         new Thread(new Runnable(){
            @Override
            public void run() {

              ld.insert(Thread.currentThread());

            }

        }).start();

         new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                ld.insert(Thread.currentThread());
            }

         }).start();
    }

    public void insert(Thread thread){

        System.out.println(lock);
        //获取锁
        if(lock.tryLock()){
            try {
                for(int i=0;i<5;i++){
                    list.add(i);
                }
                System.out.println(Thread.currentThread().getName()+"获取了锁");
            } catch (Exception e) {
                // TODO: handle exception
            }finally{
                //释放锁
                lock.unlock();
                System.out.println(Thread.currentThread().getName()+"释放了锁");
            }
        }else{
            System.out.println(Thread.currentThread().getName()+"没有获取到锁");
        }

    }

}

运行结果:

[email protected][Unlocked]
[email protected][Locked by thread Thread-0]
Thread-1没有获取到锁
Thread-0获取了锁
Thread-0释放了锁

当多个线程获取同一个锁对象时,当线程a 获取锁  b尝试获取锁失败返回false

lockInterruptibly()

package cn.ac.bcc.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class InterruptiblyDemo {

    Lock lock = new ReentrantLock();

    public static void main(String[] args) {

        InterruptiblyDemo interruptiblyDemo = new InterruptiblyDemo();

        MyThread myThread = new MyThread(interruptiblyDemo);
        MyThread myThread2 = new MyThread(interruptiblyDemo);
        myThread.start();
        myThread2.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //中断线程2
        myThread2.interrupt();
    }

    public  void  insert() throws InterruptedException{
        lock.lockInterruptibly();
        try{
            System.out.println(Thread.currentThread().getName()+"得到了锁");
            long startTime = System.currentTimeMillis();
            for(;;){

                if(System.currentTimeMillis()-startTime>=Integer.MAX_VALUE){
                    break;
                }

            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            System.out.println(Thread.currentThread().getName()+"释放了锁");
            lock.unlock();
        }
    }
}
class MyThread extends Thread{

    InterruptiblyDemo interruptiblyDemo;

    public MyThread(InterruptiblyDemo interruptiblyDemo){
        this.interruptiblyDemo=interruptiblyDemo;
    }

    @Override
    public void run(){
        try {
            interruptiblyDemo.insert();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(Thread.currentThread().getName()+"锁被中断");
        }
    }

}

运行结果:

Thread-0得到了锁
java.lang.InterruptedException
Thread-1锁被中断
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:896)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at cn.ac.bcc.lock.InterruptiblyDemo.insert(InterruptiblyDemo.java:30)
at cn.ac.bcc.lock.MyThread.run(InterruptiblyDemo.java:60)

https://www.cnblogs.com/baizhanshi/p/6419268.html

原文地址:https://www.cnblogs.com/lwdmaib/p/9266326.html

时间: 2024-08-30 07:43:11

同步锁之lock的相关文章

同步锁(lock)

有两种机制防止代码块受并发访问的干扰: 1.一个是使用synchronized关键字. 2.使用ReentrantLock类.(通过显示定义同步锁对象来实现同步.) 同步锁(lock)方法是控制多个线程对共享资源进行访问的工具.通常,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前先获得Lock对象. Lock.ReadWriteLock(读写锁)是java 5 提供的两个根接口.别为Lock接口提供了ReentrantLock(可重入锁)实现类:为R

多线程 - 线程同步锁(lock、Monitor)

1. 前言 多线程编程的时候,我们不光希望两个线程间能够实现逻辑上的先后顺序运行,还希望两个不相关的线程在访问同一个资源的时候,同时只能有一个线程对资源进行操作,否则就会出现无法预知的结果. 比如,有两个线程需要对同一个计数器加1,我们希望结果是计数器最终加2,但可能同时获取到了这个计数器,第一个线程对计数器加1,但第二个线程并不知道,于是重新对计数器加1,导致最终计数器损失了一个计数.为了解决这个问题,就必须在获取该计数器前锁定,防止其他线程再次获取,直到处理完成后再释放. Monitor.l

有关多线程(同步锁,递归锁,同步对象,信号量)

上面一个随笔已经简单介绍了多线程,比如下面在举个简单的例子: 1 #!/usr/bin/env python 2 #-*-coding:utf-8 -*- 3 4 import threading 5 import time 6 7 def add(): 8 sum = 0 9 10 for i in range(1000000): 11 sum += i 12 13 print("sum: ",sum) 14 15 16 def mul(): 17 sum2 = 1 18 for i

java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)

import java.util.concurrent.locks.*; class DuckMsg{ int size;//烤鸭的大小 String id;//烤鸭的厂家和标号 DuckMsg(){ } DuckMsg(int size, String id){ this.size=size; this.id=id; } public String toString(){ return id + " 大小为:" + size; } } class Duck{ private int

JUC--Callable 以及Lock同步锁

/** * 一.创建执行线程的方式三:实现Callable接口.相较于实现Runnable接口方式,方法可以有返回值,并且可以抛出异常 * 二.callable 需要FutureTask实现类的支持.用于接受运算结果.FutureTask是Future接口的实现类. * * 线程执行完之后才会执行result.get 可以当做闭锁看 */ public class TestCallable { public static void main(String[] args) { ThreadDemo

002-多线程-锁-同步锁-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. synchronized结论: 1.java5.0之前,协调线程间对共享对象的访问的机制只有synchronized和volatile,但是内置锁在功能上存在一些局限性,jdk5增加了Lock以及ReentrantLock. 2.java5.0,增加了一种新的机制:显式锁ReentrantLock,注意它

java基础——lock同步锁

package lock; /* 方式三: Lock锁 synchronized和lock的不同 1.sychronized在执行完相应代码块以后属于自动释放同步监视器,lock需要手动启动同步 建议优先使用lock->同步方法块->同步方法(在方法体之外) 实现Runnable对象被三个线程调用,然后这个对象的run方法里贡献资源操作器被lock上锁了 @author zsben @create 2020-01-03 23:55 */ import java.util.concurrent.

111 python程序中的进程操作-多进程同步(mulitProcessing Lock锁)

通过学习,我们使用各种方法实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制.尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题. 一.锁的基础使用 1.1多个进程抢占数据资源 from multiprocessing import Process import os import time import random def work(n): print

《GCD 实现同步锁》-07-多线程

@MicroCai 2015-03-03 23:18 字数 6539 阅读 202 Effective Objective-C Notes:GCD 实现同步锁 Archives iOS <Effective Objective-C Notes>系列博文整理自<Effective Objective-C 2.0> 如果您觉得我的博客对您有帮助,请通过关注我的新浪微博  MicroCai 支持我,谢谢! 本文名为<GCD 实现同步锁>,内容不止于锁.文章试图通过 GCD 同