精华内容
下载资源
问答
  • 线程——Lock使用

    千次阅读 2019-04-12 11:27:43
    lock关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。 Lock是一个接口,其中常用的方法有: 尝试获取锁...

    Lock介绍:

    lock关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

    Lock是一个接口,其中常用的方法有:

    • 尝试获取锁,获取成功则返回,否则阻塞当前线程
      void lock();

    • 尝试获取锁,线程在成功获取锁之前被中断,则放弃获取锁,抛出异常
      void lockInterruptibly() throws InterruptedException;

    • 尝试获取锁,获取锁成功则返回true,否则返回false
      boolean tryLock();

    • 尝试获取锁,若在规定时间内获取到锁,则返回true,否则返回false,未获取锁之前被中断,则抛出异常
      boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    • 释放锁
      void unlock();

    • 返回当前锁的条件变量,通过条件变量可以实现类似notify和wait的功能,一个锁可以有多个条件变量
      Condition newCondition();

    ReentrantLock类:

    ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java关键字synchronized隐式支持重入性,synchronized通过获取自增,释放自减的方式实现重入。与此同时,ReentrantLock还支持公平锁和非公平锁两种方式。那么,要想完完全全的弄懂ReentrantLock的话,主要也就是ReentrantLock同步语义的学习:1. 重入性的实现原理;2. 公平锁和非公平锁

    一个简单的示例:

    main函数:

    package ReentranLock;
    public class Run {
        public static void main(String[] args) {
            MyService service = new MyService();
            MyThread a1 = new MyThread(service);
            MyThread a2 = new MyThread(service);
            MyThread a3 = new MyThread(service);
            a1.start();
            a2.start();
            a3.start();
        }
    }
    

    Service类:

    package ReentranLock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyService {
        private Lock lock = new ReentrantLock();
    
        public void testMethod() {
            lock.lock();
            for (int i = 0; i < 5; i++) {
                System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
            }
            lock.unlock();
        }
    }
    

    线程类:

    package ReentranLock;
    
    public class MyThread extends Thread {
        private MyService service;
    
        public MyThread(MyService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.testMethod();
        }
    }
    

    运行结果如下:

    ThreadName=Thread-0 1
    ThreadName=Thread-0 2
    ThreadName=Thread-0 3
    ThreadName=Thread-0 4
    ThreadName=Thread-0 5
    ThreadName=Thread-1 1
    ThreadName=Thread-1 2
    ThreadName=Thread-1 3
    ThreadName=Thread-1 4
    ThreadName=Thread-1 5
    ThreadName=Thread-2 1
    ThreadName=Thread-2 2
    ThreadName=Thread-2 3
    ThreadName=Thread-2 4
    ThreadName=Thread-2 5
    

    结论为:该ReentrantLock类的lock()和unlock()方法确实可以实现线程的同步效果。


    实现等待/通知效果

    多线程——Condition的介绍以及用法

    “公平锁” 和 “非公平锁”

    公平锁:多线程获取锁的顺序是按照线程加锁的顺序来分配的。
    非公平锁:都是随机,可能造成某些线程一直无法运行。
    如何实现:
    在业务类中,生成ReentrantLock对象时,通过其参数boolean值决定是公平锁还是非公平锁。

    公平锁:
    Lock lock = new ReentrantLock(true);
    非公平锁:
    Lock lock = new ReentrantLock(false);
    

    ReentrantReadWriteLock类:

    类ReentrantLock具有完全互斥排他的效果,即同一时刻只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样做虽然保证了实例变量的安全性,但效率比较底下,所以JDK提供了ReentrantReadWriteLock类,效率更加高效,在某些不需要实例变量的方法中,完全可以使用读写锁ReentrantReadWriteLock 来提升该方法的运行速度。

    多个读锁之间不互斥,读锁和写锁之间互斥,写锁与写锁之间也互斥及,多个读操作可异步执行,读写操作须同步执行,写写操作也须同步执行。

    读读共享:

    main函数:

    package ReadWriteLockBegin1;
    
    public class Run {
        public static void main(String[] args) {
            Service service = new Service();
            ThreadA a = new ThreadA(service);
            a.setName("A");
            ThreadB b = new ThreadB(service);
            b.setName("B");
            a.start();
            b.start();
        }
    }
    

    线程类

    package ReadWriteLockBegin1;
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.read();
        }
    }
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.read();
        }
    }
    

    service类

    package ReadWriteLockBegin1;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class Service {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    
        public void read() {
            try {
                try {
                    lock.readLock().lock();
                    System.out.println("获取读锁" + Thread.currentThread().getName() + " "
                     + System.currentTimeMillis());
                    Thread.sleep(1000);
                } finally {
                    lock.readLock().unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    运行结果如下

    获取读锁A 1555038797055
    获取读锁B 1555038797055
    

    结论:两个线程几乎同时进入lock()方法后面的代码。开启两个线程同时去争抢锁,发现当锁为读锁时,两线程运行逻辑的时间时几乎一致的,即两者时异步执行的。提高了运行的效率


    写写互斥:

    main函数:

    package ReadWriteLockBegin2;
    
    public class Run {
        public static void main(String[] args) {
            Service service = new Service();
            ThreadA a = new ThreadA(service);
            a.setName("A");
            ThreadB b = new ThreadB(service);
            b.setName("B");
            a.start();
            b.start();
        }
    }
    

    线程类

    package ReadWriteLockBegin2;
    
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.write();
        }
    }
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.write();
        }
    }
    
    

    service类

    package ReadWriteLockBegin2;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class Service {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    
        public void write() {
            try {
                try {
                    lock.writeLock().lock();
                    System.out.println("获得写锁" + Thread.currentThread().getName() + " " 
                    + System.currentTimeMillis());
                    Thread.sleep(1000);
                } finally {
                    lock.writeLock().unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    

    运行结果如下

    获得写锁A 1555039240644
    获得写锁B 1555039241645
    

    结论:由结果看,写写操作是互斥的


    读写互斥:

    main函数:

    package ReadWriteLockBegin3;
    
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            Service service = new Service();
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
            Thread.sleep(1000);
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
        }
    }
    

    线程类

    package ReadWriteLockBegin3;
    
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.read();
        }
    }
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.write();
        }
    }
    

    service类

    package ReadWriteLockBegin3;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class Service {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    
        public void read() {
            try {
                try {
                    lock.readLock().lock();
                    System.out.println("获得读锁" + Thread.currentThread().getName() + " " 
                    + System.currentTimeMillis());
                    Thread.sleep(1000);
                } finally {
                    lock.readLock().unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void write() {
            try {
                try {
                    lock.writeLock().lock();
                    System.out.println("获得写锁" + Thread.currentThread().getName() + " " 
                    + System.currentTimeMillis());
                    Thread.sleep(1000);
                } finally {
                    lock.writeLock().unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    运行结果如下

    获得读锁A 1555039499243
    获得写锁B 1555039500245
    

    结论:读线程和写线程时同步的,说明读写是互斥的。


    下一篇将总结synchronized和Lock的区别,两者的实现原理以及volatile关键字的使用和原理等看完《Java并发艺术》之后再总结。

    展开全文
  • c#多线程中Lock()关键字的使用

    万次阅读 2013-05-22 16:57:36
    本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。 每个线程都有自己的资源,但是代码区是...

    本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。

    每个线程都有自己的资源,但是代码区是共享的,即每个线程都可以执行相同的函数。这可能带来的问题就是几个线程同时执行一个函数,导致数据的混乱,产生不可预料的结果,因此我们必须避免这种情况的发生。

    其中,lock是一种比较好用的简单的线程同步方式,它是通过为给定对象获取互斥锁来实现同步的。它可以保证当一个线程在关键代码段的时候,另一个线程不会进来,它只能等待,等到那个线程对象被释放,也就是说线程出了临界区。用法:

    public void Function()
    {
        object lockThis = new object ();
        lock (lockThis)
        {
            // Access thread-sensitive resources.
        }
    }

    下面是一个比较典型的使用C#  lock关键字的例子,其中在注释里说明了C# lock关键字的用法和用途。

    Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->using System; 
    using System.Threading; 
    namespace ThreadSimple
    { 
        internal class Account
        { 
            int balance; //余额
            Random r=new Random(); 
            internal Account(int initial)  
            {  
                balance=initial; 
            }
            internal int Withdraw(int amount) //取回、取款
            { 
                if(balance<0) 
                {  
                    //如果balance小于0则抛出异常  
                    throw new Exception("NegativeBalance");//负的 余额 
                } 
                //下面的代码保证在当前线程修改balance的值完成之前 
                //不会有其他线程也执行这段代码来修改balance的值  
                //因此,balance的值是不可能小于0的  
                lock(this)  
                { 
                    Console.WriteLine("CurrentThread:"+Thread.CurrentThread.Name); 
                    //如果没有lock关键字的保护,那么可能在执行完if的条件判断(成立)之后  
                    //另外一个线程却执行了balance=balance-amount修改了balance的值 
                    //而这个修改对这个线程是不可见的,所以可能导致这时if的条件已经不成立了 
                    //但是,这个线程却继续执行 balance=balance-amount,所以导致balance可能小于0 
                    if(balance>=amount) 
                    { 
                        Thread.Sleep(5);
                        balance=balance-amount; 
                        return  amount; 
                    }  else 
                    { 
                        return 0;
                        //transactionrejected 
                    } 
                }  
            }
            internal void DoTransactions()//取款事务
            {
                for (int i = 0; i < 100; i++)
                {
                    Withdraw(r.Next(-50, 100));
                }
            }
        }   
    
        internal class Test  
        {  
            static internal Thread[] threads=new Thread[10]; 
            public static void Main()  
            {  
                Account acc=new Account(0); 
                for(int i=0;i<10;i++) 
                {  
                    Thread t=new Thread(new ThreadStart(acc.DoTransactions));
                    threads[i]=t; 
                }
                for (int i = 0; i < 10; i++)
                {
                    threads[i].Name = i.ToString();
                }
                for (int i = 0; i < 10; i++)
                {
                    threads[i].Start();
                    Console.ReadLine();
                }
            }
        } 
    }

    lock的参数必须是基于引用类型的对象,不要是基本类型像bool,int什么的,这样根本不能同步,原因是lock的参数要求是对象,如果传入int,势必要发生装箱操作,这样每次lock的都将是一个新的不同的对象。最好避免使用public类型或不受程序控制的对象实例,因为这样很可能导致死锁。特别是不要使用字符串作为lock的参数,因为字符串被CLR“暂留”,就是说整个应用程序中给定的字符串都只有一个实例,因此更容易造成死锁现象。建议使用不被“暂留”的私有或受保护成员作为参数。其实某些类已经提供了专门用于被锁的成员,比如Array类型提供SyncRoot,许多其它集合类型也都提供了SyncRoot。

    所以,使用lock应该注意以下几点: 
    1、如果一个类的实例是public的,最好不要lock(this)。因为使用你的类的人也许不知道你用了lock,如果他new了一个实例,并且对这个实例上锁,就很容易造成死锁。
    2、如果MyType是public的,不要lock(typeof(MyType))。
    3、永远也不要lock一个字符串。


    展开全文
  • 线程同步Lock

    万次阅读 2017-04-25 23:41:19
    转载请标明出处: ... 本文出自:【顾林海的博客】 前言除了上一篇文章的synchronized,Java还提供了同步代码块的另一种机制,这种机制基于Lock接口及其实现类。...关于线程相关知识可以查看:《有关线程的相关知识

    转载请标明出处:
    http://blog.csdn.net/hai_qing_xu_kong/article/details/70768583
    本文出自:【顾林海的博客】


    前言

    除了上一篇文章的synchronized,Java还提供了同步代码块的另一种机制,这种机制基于Lock接口及其实现类。相比与synchronized来说更强大也更灵活。

    关于线程相关知识可以查看:

    有关线程的相关知识(1)
    有关线程的相关知识(2)

    关于synchronized的相关知识可以查看:

    线程同步synchronized

    Lock的使用

    使用Lock能支持更灵活的同步代码块结构,也就是控制的获取和释放不出现在同一个块结构中。Lock接口提供了很多的功能,可以通过tryLock()方法来试图获取锁,如果锁已经被其他线程获取,它将返回false并继续往下执行代码。Lock接口允许分离读和写操作,允许多个读线程和只有一个写线程。

    下面编写一个使用Lock接口和它的实现类ReentrantLock类来创建一个临界区:

    public class Queue {
    
        // 声明一个锁对象,并且用ReentrantLock类初始化
        private final Lock queueLock = new ReentrantLock();
    
        /**
         * 打印信息 通过调用lock()方法获取对锁对象的控制
         */
        public void printJob() {
            queueLock.lock();
            System.out.println("正在打印信息..."+new Date());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                queueLock.unlock();
            }
        }
    
    }
    public class Event implements Runnable{
    
        private Queue queue;
    
        public Event(Queue queue){
            this.queue=queue;
        }
    
        @Override
        public void run() {
            queue.printJob();
        }
    
    }
    public class Client {
        public static void main(String[] args) {
            Queue queue=new Queue();
    
            Event event=new Event(queue);
    
            Thread[] thread=new Thread[10];
    
            for(int i=0,length=thread.length;i<length;i++){
                thread[i]=new Thread(event);
            }
    
            for(int i=0,length=thread.length;i<length;i++){
                thread[i].start();
            }
    
        }
    }

    上面Queue类中,定义来printJob()方法,通过lock()方法获取对锁对象的控制,最后通过unlock()方法释放对锁对象的控制。在主类中创建了10个线程,并启动这10个线程,运行程序,会在控制台上每隔1秒打印信息。

    运行程序:
    正在打印信息...Tue Apr 25 22:02:31 CST 2017
    正在打印信息...Tue Apr 25 22:02:32 CST 2017
    正在打印信息...Tue Apr 25 22:02:33 CST 2017
    正在打印信息...Tue Apr 25 22:02:34 CST 2017
    正在打印信息...Tue Apr 25 22:02:35 CST 2017
    正在打印信息...Tue Apr 25 22:02:36 CST 2017
    正在打印信息...Tue Apr 25 22:02:37 CST 2017
    正在打印信息...Tue Apr 25 22:02:38 CST 2017
    正在打印信息...Tue Apr 25 22:02:39 CST 2017
    正在打印信息...Tue Apr 25 22:02:40 CST 2017

    通过运行结果可以看出,对临界区的访问通过锁,来实现同一时间只有一个执行线程访问这个临界区,这里通过lock()方法获取对锁的控制,当某个线程访问这个方法时,如果没有其他线程获取对这个锁的控制,lock()方法将得到并且允许它立刻执行临界区。在线程离开临界区的时候,我们必须使用unlock()方法来释放它持有的锁,以让其他线程访问临界区,如果在离开临界区没有调用unlock()方法释放它持有的锁,其他线程将永远等待,从而导致死锁。


    除了使用lock()方法来获取锁之外,Lock接口还提供了另一个方法来获取锁,即tryLock()方法。与lock()方法不同之处在于线程使用tryLock()不能够获取锁,tryLock()会立即返回,它不会将线程置入休眠,返回true表示线程获取了锁,false表示没有获取锁。


    使用读写锁实现同步数据访问

    ReadWriteLock接口和它唯一实现类ReentrantReadWriteLock,一个是读操作锁,另一个是写操作锁。使用读操作锁时可以允许多个线程同时访问,使用写操作锁时只允许一个线程进行。在一个线程执行写操作时,其他线程不能够执行读操作。

    接下来通过ReadWriteLock接口来编写对某个对象的访问。

    public class Product {
    
        private int number1;
        private int number2;
    
        private ReadWriteLock lock;
    
        public Product() {
            number1 = 10;
            number2 = 20;
            lock = new ReentrantReadWriteLock();
        }
    
        /**
         * 通过读锁获取对这个属性的访问
         * 
         * @return number1
         */
        public int getNumber1() {
            lock.readLock().lock();
            int number = number1;
            lock.readLock().unlock();
            return number;
        }
    
        /**
         * 通过读锁获取对这个属性的访问
         * 
         * @return number2
         */
        public int getNumber2() {
            lock.readLock().lock();
            int number = number2;
            lock.readLock().unlock();
            return number;
        }
    
        /**
         * 使用写锁来控制对这两个属性的访问
         * 
         * @param number1
         * @param number2
         */
        public void setNumber(int number1, int number2) {
            lock.writeLock().lock();
            System.out.println("写入number1:"+number1+"和number2:"+number2);
            this.number1 = number1;
            this.number2 = number2;
            lock.writeLock().unlock();
        }
    
    }
    
    /**
     * 读取类,读取Product的number1和number2
     * 
     * @author gulinhai
     *
     */
    public class Reader implements Runnable {
    
        private Product product;
    
        public Reader(Product product) {
            this.product = product;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("number1=" + product.getNumber1() + ";number2=" + product.getNumber2());
            }
        }
    
    }
    
    /**
     * 写入类,修改number1和number2
     * @author gulinhai
     *
     */
    public class Writer implements Runnable {
    
        private Product product;
    
        public Writer(Product product) {
            this.product = product;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
    
                product.setNumber(i, i * 2);
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    public class Client {
        public static void main(String[] args) {
            Product product = new Product();
    
            Reader[] reader = new Reader[5];
            Thread[] readerThread = new Thread[5];
    
            for (int i = 0, length = readerThread.length; i < length; i++) {
                reader[i] = new Reader(product);
                readerThread[i] = new Thread(reader[i]);
            }
    
            Writer writer = new Writer(product);
            Thread writerThread = new Thread(writer);
    
            for (int i = 0, length = readerThread.length; i < length; i++) {
                readerThread[i].start();
            }
            writerThread.start();
    
        }
    }
    
    运行结果:
    写入number1:0number2:0
    写入number1:1number2:2
    number1=1;number2=2
    number1=1;number2=2
    number1=1;number2=2
    number1=1;number2=2
    number1=1;number2=2
    写入number1:2number2:4
    number1=2;number2=4
    number1=2;number2=4
    number1=2;number2=4
    number1=2;number2=4
    number1=2;number2=4
    写入number1:3number2:6
    number1=3;number2=6
    number1=3;number2=6
    number1=3;number2=6
    写入number1:4number2:8
    number1=4;number2=8
    number1=3;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    number1=4;number2=8
    

    通过输出结果可以看出合理的利用ReentrantReadWriteLock类的两种锁,可以有效的避免数据不一致的问题。

    ReentrantLock和ReentrantReadWriteLock类的构造器都含有一个布尔参数,它允许你控制这个两个类的行为,默认值是false,称为非公平模式,在非公平模式下,当有很多线程在等待锁时,锁将选择他们中的一个来访问临界区,这个选择是没有任何约束的。当布尔值为true时,称为公平模式,在公平模式下,当有很多线程在等待锁时,锁将选择它们中的一个来访问临界区,而且选择的是等待时机最长的。


    锁中使用多条件

    一个锁可能关联一个或者多个条件,这些条件通过Condition接口声明,目的允许线程获取锁并且查看等待的某一个条件是否满足,如果不满足就挂起直到某个线程唤醒它们,Condition接口提供了挂起线程和唤起线程的机制。

    编程程序,利用Condition来解决生产者-消费者问题。

    /**
     * 创建数据存储类EventStorage,并保存一个最大值maxSize和数据集合 LinkedList<Date>来保存存入的日期。
     * 
     * @author gulinhai
     *
     */
    public class EventStorage {
    
        private int maxSize;
        private LinkedList<Date> storage;
    
        private ReentrantLock lock;
    
        private Condition condition1;
        private Condition condition2;
    
        public EventStorage() {
            lock = new ReentrantLock();
            condition1 = lock.newCondition();
            condition2 = lock.newCondition();
            this.maxSize = 10;
            this.storage = new LinkedList<>();
        }
    
        public int size() {
            return storage.size();
        }
    
        /**
         * <pre>
         * 获取锁,检查这个缓冲区是否满了,如果缓冲区满了,
         * 就调用条件condition1的await()方法
         * 等待空位出现,当其他线程调用条件condition1的
         * signal()或者signalAll()方法时,这个线程
         * 将被唤醒,在有空位后,线程会将数据保存到缓冲区中,
         * 并调用条件condition2的signalAll()方法。
         * </pre>
         */
        public void set() {
            lock.lock();
            try {
                while (storage.size() == maxSize) {
                    condition1.await();
                }
                storage.add(new Date());
                condition2.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
        }
    
        /**
         * <pre>
         * 获取锁,检查这个缓冲区是否为空,如果缓冲区为空,
         * 就调用条件condition2的await()方法
         * 等待数据出现,当其他线程调用条件condition2的
         * signal()或者signalAll()方法时,这个线程
         * 将被唤醒,在有数据后,线程会从缓冲区中取出数据,
         * 并调用条件condition1的signalAll()方法。
         * </pre>
         */
        public void get() {
            lock.lock();
            try {
                while (storage.size() == 0) {
                    condition2.await();
                }
                storage.poll();
                condition1.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
        }
    
    }
    
    /**
     * 生产者
     * @author gulinhai
     *
     */
    public class Producer implements Runnable{
    
        private EventStorage storage;
    
        public Producer(EventStorage storage){
            this.storage=storage;
        }
    
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                storage.set();
            }
        }
    
    }
    
    /**
     * 消费者
     * @author gulinhai
     *
     */
    public class Consumber implements Runnable{
    
        private EventStorage storage;
    
        public Consumber(EventStorage storage){
            this.storage=storage;
        }
    
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                storage.get();
            }
        }
    
    }
    
    public class Client {
    
        public static void main(String[] args) {
            EventStorage storage=new EventStorage();
    
            Producer producer=new Producer(storage);
            Thread producerThread=new Thread(producer);
    
            Consumber consumber=new Consumber(storage);
            Thread consumberThread=new Thread(consumber);
    
            producerThread.start();
            consumberThread.start();
    
            try {
                producerThread.join();
                consumberThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("缓冲区数据个数:"+storage.size());
    
        }
    
    }
    
    输出结果:
    缓冲区数据个数:0

    与锁绑定的所有条件对象都是通过Lock接口声明的newCondition()方法创建的,在使用条件的时候,必须获取这个条件绑定的锁,所以带条件的代码必须在调用Lock对象的lock()方法和unlock()方法之间,当线程调用条件的await()方法时,它将自动释放这个条件绑定的锁,其他某个线程才可以获取这个锁并且执行相同的操作,或者执行这个锁保护的另一个临界区代码。

    展开全文
  • C# 关于线程lock使用方法

    万次阅读 多人点赞 2016-09-02 10:07:05
    在某些情况下,我们希望A的代码块(B)同步的执行,即同一时刻只有一个线程执行代码块B,这就需要用到锁(lock)。lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。它可以把一段代码定义为互斥段...

            在多线程编程中,可能会有许多线程并发的执行一段代码(代码块A),以提高执行效率。在某些情况下,我们希望A中的代码块(B)同步的执行,即同一时刻只有一个线程执行代码块B,这就需要用到锁(lock)。lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。

    其写法如下:

    Object  locker = new Object();

    lock(locker)

    {

          B    //同步执行的代码

    }

    其相当于如下代码:

    //System.Threading.Moniter.enter(Object),Moniter提供同步访问对象的机制,enter方法在指定对象上获取排他锁,之后其他线程不能再次获取,直到释放

    Monitor.enter(locker); 
    {
          B
    }
    Monitor.exit(locker); 
    //exit(Object)释放指定对象上的排他锁。

    lock 语句的表达式必须表示一个引用类型的值永远不会为 lock 语句中的表达式执行隐式装箱转换,因此,如果该表达式表示的是一个值类型的值,则会导致一个编译时错误。

    C#中引用类型主要有:数组、类、接口、委托、object、字符串,但是最好不要锁字符串;使用lock同步时,应保证lock的是同一个对象,而给字符串变量赋值并不是修改它,而是重新创建了新的对象,这样多个线程以及每个循环之间所lock的对象都不同,因此达不到同步的效果。常用做法是创建一个object对象,并且永不赋值。

    下面举个简单的例子,一群苦逼程序员被逼捐款,每人100:




    展开全文
  • 一个正在运行的应用程序在操作系统被视为一个进程,进程可以包括一个或多个线程线程是操作系统分配处理器时间的基本单元,在进程可以有多个线程同时执行代码。进程之间是相对独立的,一个进程无法访问另一个...
  • java多线程Lock使用

    千次阅读 2017-05-06 00:44:26
    在Java多线程中,可以使用synchronized关键字来实现线程之间的同步互斥,也就是上锁。在JDK1.5之,新增了ReentrantLock类也能够达到相同的效果。并且在扩展功能上更强、更加灵活。LockLock是一个接口,也就是...
  • Java多线程-Lock锁的使用

    千次阅读 2019-03-15 13:42:08
    文章目录Lock锁的使用Lock接口1.1 Lock接口简介1.2 Lock的简单使用1.3 Lock接口的特性和常见方法二 Lock接口的实现类:ReentrantLock2.1 第一个ReentrantLock程序2.2 Condition接口简介2.3 使用Condition实现等待...
  • java5提出了Lock对象,比起synchronized,Lock对象特别灵活 先说下Lock的基本方法 lock() 获得锁 unlock() 释放锁 这2个方法其实就是Lock比之前...Condition是Lock中使用等待/通知的类使用方法如下 Lock ...
  • 线程中lock用法及使用细节的经典实例 一、Lock定义  lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程...
  • Android多线程研究(9)——线程Lock

    万次阅读 多人点赞 2014-06-08 21:08:55
    在前面我们在解决线程同步问题的时候使用了synchronized关键字,今天我们来看看Java 5.0以后提供的线程Lock.Lock接口的实现类提供了比使用synchronized关键字更加灵活和广泛的锁定对象操作,而且是以面向对象的...
  • android 线程Lock

    千次阅读 2017-09-20 08:41:17
    Lock使用。 这个其实和SynchronizedClass 是一样的。我记得我的一篇博客写过这个内容。再次记录一下。 一、同步机制关键字synchronized 对于java来说,最常用的同步机制就是synchronized关键字,他是一种...
  • java多线程Lock类的使用

    千次阅读 2016-09-26 23:35:59
    1.ReentrantLock类的使用  1.1ReentrantLock实现线程间同步 public class MyService { private Lock lock=new ReentrantLock(); public void service(){ lock.lock(); for(int i=0;i;i++){ System.out...
  • 线程安全与线程同步及lock使用

    千次阅读 2019-12-30 17:41:58
    线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全:就是不提供...
  • python多线程中Lock()与RLock()锁

    万次阅读 2017-05-29 01:38:54
    资源总是有限的,程序运行如果对同一个对象进行操作,则有可能...3.threading.Lock() 加载线程的锁对象,是一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取4.threading.RLock() 多重锁,在
  • Java高级-线程同步lock与unlock使用

    千次阅读 2017-05-26 15:34:35
    原文: ... 一、Lock与Synchronized区别 Java可以使用Lock和Synchronized的可以实现对某个共享资源的同步,同时也可以实现对...Lock可以使用Condition进行线程之间的调度,Synchronized则使用Object对象本身的notify,
  • Java多线程Lock使用

    万次阅读 多人点赞 2011-12-21 09:48:37
    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;...import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWr
  • python多线程Lock()

    千次阅读 2018-10-21 12:55:26
    Lock用于锁定。job1和job2对同一个全局变量操作。 import threading def job1(): global A,lock lock.acquire() for i in range(10): A+=1 print("job1",A) lock.release() def job2(): global...
  • 调用了n次acquire锁请求,则必须调用n次的release才能在线程中释放锁对象 threading.Lock() 加载线程的锁对象,是一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取 threading.RLock() ...
  • java多线程-Lock(八)

    千次阅读 2018-08-07 10:04:23
    线程使用synchronized来保持线程之间同步互斥,jdk1.5加入了Lock对象也能实现同步效果 ReentrantLock(rɪ’entrənt)类的使用 ReentrantReadWriteLock类的使用 ReentrantLock java.util.concurrent....
  • 本文中将主要介绍Java多线程编程基础Lock锁对象的使用,以及如何一步一步实现Java代码的生产者与消费者; 1、Java如何使用Lock锁以及死锁问题的描述 2、Java实现生产者与消费者的过程(一步一步优化的步骤...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 400,698
精华内容 160,279
关键字:

线程中lock的使用