精华内容
下载资源
问答
  • 并发控制的方法

    千次阅读 2015-10-19 14:56:13
    一、volatile ...它是最常用的同步方法之一,简洁明了,代码可读性和维护性好。jdk6中,性能也有很大 改进。 为了有效地控制线程间协作,需要配合使用synchronized以及notify()和wait()等方法。 三、Ree

    一、volatile

    使用volatile标识变量,将迫使所有线程均读写主内存中的对应变量,从而使得volatile变量在多线程间可见。

    二、同步关键字synchronized

    它是最常用的同步方法之一,简洁明了,代码可读性和维护性好。jdk6中,性能也有很大 的改进。

    为了有效地控制线程间的协作,需要配合使用synchronized以及notify()和wait()等方法。

    三、ReentrantLock重入锁

    功能强大,可中断、可定时。使用完成后,务必释放锁。

    四、ReadWriteLock读写锁

    在读多写少的场合,使用读写锁可以分离读操作和写操作,使所有读操作间真正并行,因此,能够有效提高系统的并发能力。

    五、Condition对象

    await()方法:会使当前线程等待,同时释放当前锁,其他线程中使用signal()或者signalAll()方法时,线程会重新获得 锁并继续执行。或者当线程被中断时,也能跳出等待。

    signal()方法:用于唤醒一个在等待中的线程。

    六、Semaphore信号量

    无论是内部锁synchronized还是重入锁ReentrantLock,一次都只允许一个线程访问一个资源,而信号量却可以指定多个线程同时访问某一个资源。

    七、ThreadLocal线程局部变量

    ThreadLocal完全不提供锁,而使用以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全,因此它不是一种数据共享的解决方案。


    展开全文
  • java并发控制常用api

    2018-04-26 10:29:25
    sleep(long millis)在指定毫秒数内让当前正在执行线程休眠(暂停执行),属于Thread类中的方法。在调用sleep()方法的过程中,线程不会释放对象锁。依然持有着锁入眠,也就是说如果有synchronized同步快,其他...
    1. sleep(long millis)
    在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),属于Thread类中的方法。在调用sleep()方法的过程中,线程不会释放对象锁。依然持有着锁入眠,也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。等待睡眠时间到了之后进入线程进入就绪状态。sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。
    1. wait()和notify()、notifyAll()
    三个方法都是Object类中的方法,这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用。synchronized关键字用于保护共享数据,阻止其他线程对共享数据的存取,但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出synchronized数据块时让其他线程也有机会访问共享数据呢?此时就用这三个方法来灵活控制。 
    常用的wait方法有wait()和wait(long timeout);
    void wait() wait方法与sleep方法相同之处是在于都是让线程进入等待的状态,的与sleep方法不同之处在于:使用wait方法进入等待的线程会主动释放持有的锁。在其他线程调用此对象的 notify() 方法或者 notifyAll()方法前,导致当前线程等待。注意:notify不会释放锁 
    void wait(long timeout)在其他线程调用此对象的notify() 方法 或者 notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。 
    wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其他synchronized数据可被别的线程使用。wait()notify()因为会对对象的“锁标志”进行操作,所以他们必需在Synchronized函数或者 synchronized block 中进行调用。如果在non-synchronized 函数或 non-synchronized block 中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常
    在生产者与消费者的场景中,要使用notifyAll而不是用notify,notify会导致死锁出现。

    1. yield()
    是Thread中的方法。暂停当前正在执行的线程对象,并执行其他线程。该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
    package com.multithread.yield;  
    class ThreadYield extends Thread{  
        public ThreadYield(String name) {  
            super(name);  
        }  
       
        @Override  
        public void run() {  
            for (int i = 1; i <= 50; i++) {  
                System.out.println("" + this.getName() + "-----" + i);  
                // 当i为30时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行)  
                if (i ==30) {  
                    this.yield();  
                }  
            }  
          
    }  
    }  
      
    public class Main {  
      
        public static void main(String[] args) {  
              
            ThreadYield yt1 = new ThreadYield("张三");  
            ThreadYield yt2 = new ThreadYield("李四");  
            yt1.start();  
            yt2.start();  
        }  
      

    运行结果:
    第一种情况:李四(线程)当执行到30时会CPU时间让掉,这时张三(线程)抢到CPU时间并执行。
    第二种情况:李四(线程)当执行到30时会CPU时间让掉,这时李四(线程)抢到CPU时间并执行。
    sleep()和yield()的区别
            sleep()和yield()的区别):sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
            sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是由程序设定的,yield 方法使当前线程让出 CPU 占有权,但让出的时间是不可设定的。实际上,yield()方法对应了如下操作:先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把 CPU  的占有权交给此线程,否则,继续运行原来的线程。所以yield()方法称为“退让”,它把运行机会让给了同等优先级的其他线程
           另外,sleep 方法允许较低优先级的线程获得运行机会,但 yield()  方法执行时,当前线程仍处在可运行状态,所以,不可能让出较低优先级的线程些时获得 CPU 占有权。在一个运行系统中,如果较高优先级的线程没有调用 sleep 方法,又没有受到 I\O 阻塞,那么,较低优先级线程只能等待所有较高优先级的线程运行结束,才有机会运行。 
    1. join()
    join是Thread类的一个方法,启动线程后直接调用,即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
    使用时的代码: Thread t = new AThread(); t.start(); t.join();  
    为什么要用join()方法
    在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
    不加join。
    package com.multithread.join;  
    class Thread1 extends Thread{  
        private String name;  
        public Thread1(String name) {  
            super(name);  
           this.name=name;  
        }  
        public void run() {  
            System.out.println(Thread.currentThread().getName() + " 线程运行开始!");  
            for (int i = 0; i < 5; i++) {  
                System.out.println("子线程"+name + "运行 : " + i);  
                try {  
                    sleep((int) Math.random() * 10);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
            System.out.println(Thread.currentThread().getName() + " 线程运行结束!");  
        }  
    }  
      
    public class Main {  
      
        public static void main(String[] args) {  
            System.out.println(Thread.currentThread().getName()+"主线程运行开始!");  
            Thread1 mTh1=new Thread1("A");  
            Thread1 mTh2=new Thread1("B");  
            mTh1.start();  
            mTh2.start();  
            System.out.println(Thread.currentThread().getName()+ "主线程运行结束!");  
      
        }  
      
    }  
    输出结果:
    main主线程运行开始!
    main主线程运行结束!
    B 线程运行开始!
    子线程B运行 : 0
    A 线程运行开始!
    子线程A运行 : 0
    子线程B运行 : 1
    子线程A运行 : 1
    子线程A运行 : 2
    子线程A运行 : 3
    子线程A运行 : 4
    A 线程运行结束!
    子线程B运行 : 2
    子线程B运行 : 3
    子线程B运行 : 4
    B 线程运行结束!
    发现主线程比子线程早结束

    加join
    public class Main {  
      
        public static void main(String[] args) {  
            System.out.println(Thread.currentThread().getName()+"主线程运行开始!");  
            Thread1 mTh1=new Thread1("A");  
            Thread1 mTh2=new Thread1("B");  
            mTh1.start();  
            mTh2.start();  
            try {  
                mTh1.join();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            try {  
                mTh2.join();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println(Thread.currentThread().getName()+ "主线程运行结束!");  
      
        }  
      
    }  
    运行结果:
    main主线程运行开始!
    A 线程运行开始!
    子线程A运行 : 0
    B 线程运行开始!
    子线程B运行 : 0
    子线程A运行 : 1
    子线程B运行 : 1
    子线程A运行 : 2
    子线程B运行 : 2
    子线程A运行 : 3
    子线程B运行 : 3
    子线程A运行 : 4
    子线程B运行 : 4
    A 线程运行结束!
    主线程一定会等子线程都结束了才结束

    1. await、signal、signalAll

    Condition类中的方法,相对于wait/notify来说,await/signal方法可以用来更准确的指定叫醒哪些线程。在使用时,同样也是要先获取对象的锁。


    1. run和start()
    把需要处理的代码放到run()方法中,start()方法启动线程将自动调用run()方法,这个由java的内存机制规定的。并且run()方法必需是public访问权限,返回值类型为void。
    1. Callable接口和Runnable接口的区别
    两个接口非常相似,Callable接口内只有一个call方法,用于定义一个线程执行的操作;Runnable接口内只有一个run方法,也是用于线程执行的操作。区别在于call方法是带返回值的,而run方法是不带返回值的。且call方法是可以抛出异常的,而run方法是没有的。


    展开全文
  • 1.2.1 构造方法 1.2.2 countDown方法 1.2.3 await方法 1.3 CDL不可重复使用 2 CyclicBarrier类使用 2.1 CyclicBarrier用法 2.2 CyclicBarrier原理 2.2.1 构造方法 2.2.2 await方法 2.3 CyclicBarrier可重复...

    目录

    1 CountDownLatch类使用

    1.1 CountDownLatch用法

    1.2 CountDownLatch原理

    1.2.1 构造方法

    1.2.2 countDown方法

    1.2.3 await方法

    1.3 CDL不可重复使用

    2 CyclicBarrier类使用

    2.1 CyclicBarrier用法

    2.2 CyclicBarrier原理

    2.2.1 构造方法

    2.2.2 await方法

    2.3 CyclicBarrier可重复使用

    3 Semaphore类使用

    3.1 Semaphore用法

    3.2 Semaphore原理

    3.2.1 构造方法

    3.2.2 acquire方法

    3.2.3 release方法


    针对并发问题,JUC提供了一些工具类,来控制线程并发数。常用的有CountDownLatch、CyclicBarrier和Semaphore
    CountDownLatch:数值减掉0开始执行某个步骤
    CyclicBarrier:数值加到某个数值开始执行某个步骤
    Semaphore:控制并发线程数

    1 CountDownLatch类使用

    1.1 CountDownLatch用法

    假设教室里有5个人,最后一个人走的时候班长关门,要实现这个功能
    测试代码

    @Test
    public void testCountDownLatch() throws InterruptedException {
        int count = 5;
        CountDownLatch countDownLatch = new CountDownLatch(count);
        for (int i = 0; i < count; i ++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println(finalI + "离开");
                // 使用后把count - 1
                countDownLatch.countDown();
            }).start();
        }
        // 这里进行阻塞
        countDownLatch.await();
        System.out.println("关门 ……");
    }

    输出
    0离开
    1离开
    4离开
    3离开
    2离开
    关门 ……

    1.2 CountDownLatch原理

    CountDownLatch内部也是维护了一个基于AQS实现的一个线程同步工具不了解AQS的同学可以先看看笔者前面写的

    1.2.1 构造方法

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
    
        Sync(int count) {
            setState(count);
        }

    是不是很眼熟,count的值实际上就是设置了AQS的state属性

    1.2.2 countDown方法

    public void countDown() {
        sync.releaseShared(1);
    }

    releaseShared是AQS的一个模版方法,笔者在讲解AQS的时候已经简单提到过,这里不再赘述,直接看tryReleaseShared

    protected boolean tryReleaseShared(int releases) {
        for (;;) {
            // 获取当前state
            int c = getState();
            if (c == 0)
                return false;
            // 把state - 1 并CAS修改
            int nextc = c-1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }

    阅读源码可知countDown方法实际上就是把资源状态属性state值进行减一

    1.2.3 await方法

    如果count > 0,await方法则阻塞,直到count减成0

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }


    在讲解AQS文章中笔者提到过acquireShared方法,acquireSharedInterruptibly方法类似,只是多了一个线程中断判断,这里不再cp
    下面直接看tryAcquireShared方法

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    这里可以看到如果state==0,则返回值是1,>0,所以这里直接返回,不会进入doAcquireShared方法
    如果state!=0,则返回值是-1,<0,进入doAcquireShared方法进行等待。
    doAcquireShared方法笔者也不是很懂,只知道把当前线程添加到队列里等待运行,有兴趣的同学可以阅读以下源码

    1.3 CDL不可重复使用

    CDL是一次性的,使用完后就失效了,不能再做并发控制
    测试代码

    @Test
    public void testCountDownLatch() throws InterruptedException {
        int count = 5;
        CountDownLatch countDownLatch = new CountDownLatch(count);
        for (int i = 0; i < count; i ++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println(finalI + "离开");
                // 使用后把count - 1
                countDownLatch.countDown();
            }).start();
        }
        // 这里进行阻塞
        countDownLatch.await();
        System.out.println("关门 ……");
        TimeUnit.SECONDS.sleep(1);
        for (int i = 0; i < count; i ++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println(finalI + "离开");
                // 使用后把count - 1
                countDownLatch.countDown();
            }).start();
        }
        // 这里进行阻塞
        countDownLatch.await();
        System.out.println("关门 ……");
    }

    输出
    0离开
    1离开
    3离开
    2离开
    4离开
    关门 ……
    0离开
    1离开
    关门 ……
    2离开
    3离开
    4离开

    2 CyclicBarrier类使用

    2.1 CyclicBarrier用法

    CyclicBarrier和CDL类使用差不多,只不过CDL的count是递减的,CyclicBarrier的count是递增的
    这里简单实现一个小功能,集齐七颗龙珠召唤神龙

    @Test
    public void testCyclicBarrier() throws InterruptedException {
        int count = 7;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count, () -> System.out.println("召唤神龙 ……"));
        for (int i = 0; i < count; i ++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println(finalI + "龙珠");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    输出:
    0龙珠
    2龙珠
    1龙珠
    4龙珠
    3龙珠
    5龙珠
    6龙珠
    召唤神龙 ……

    2.2 CyclicBarrier原理

    2.2.1 构造方法

    // 第一个参数是屏障大小,第二个参数是达到parties后的执行方法

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

    2.2.2 await方法

    await方法就是一次次判断count是否等于0,如果等于0则执行目标方法,否则循环等待。

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
    
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
            final Generation g = generation;
    
            if (g.broken)
                // 如果屏障已损坏则抛异常
                throw new BrokenBarrierException();
    
            if (Thread.interrupted()) {
                // 如果线程是中断的则破坏屏障,抛异常
                breakBarrier();
                throw new InterruptedException();
            }
    
            // count - 1
            int index = --count;
            if (index == 0) {  // tripped
                // 如果-1后=0则运行目标方法barrierCommand
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    // 执行完目标方法后重置屏障,也是因为有这个方法,CyclicBarrier是可以复用的
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }
    
            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }
    
                if (g.broken)
                    throw new BrokenBarrierException();
    
                if (g != generation)
                    return index;
    
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

    2.3 CyclicBarrier可重复使用

    前面分析到执行完目标方法后调用nextGeneration方法重置屏障,所以是可以复用的
    测试代码

    @Test
    public void testCyclicBarrier() throws InterruptedException {
        int count = 7;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count, () -> System.out.println("召唤神龙 ……"));
        for (int i = 0; i < count; i ++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println(finalI + "龙珠");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    
        TimeUnit.SECONDS.sleep(1);
        System.out.println("休息一年");
    
        for (int i = 0; i < count; i ++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println(finalI + "龙珠");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    输出
    1龙珠
    0龙珠
    3龙珠
    2龙珠
    4龙珠
    5龙珠
    6龙珠
    召唤神龙 ……
    休息一年
    0龙珠
    1龙珠
    2龙珠
    3龙珠
    4龙珠
    5龙珠
    6龙珠
    召唤神龙 ……

    3 Semaphore类使用

    Semaphore可以保证获取某一个资源的最大并发数不能超过某个值,否则阻塞等待
    7辆车,3个车位,只有车位中的车离开了,其他车才能继续使用。那么我们就可以通过Semaphore来实现

    3.1 Semaphore用法

    @Test
    public void testSemaphore() throws InterruptedException {
        int count = 3;
        Semaphore semaphore = new Semaphore(count);
        for (int i = 0; i < 7; i ++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(DateUtil.datetimeToString(new Date()) + ":" + Thread.currentThread().getName() + "抢到车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(DateUtil.datetimeToString(new Date()) + ":" + Thread.currentThread().getName() + "释放车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            }).start();
        }
        TimeUnit.MINUTES.sleep(1);
    }


    输出
    2020-06-25 18:46:48:Thread-1抢到车位
    2020-06-25 18:46:48:Thread-2抢到车位
    2020-06-25 18:46:48:Thread-0抢到车位
    2020-06-25 18:46:51:Thread-1释放车位
    2020-06-25 18:46:51:Thread-0释放车位
    2020-06-25 18:46:51:Thread-2释放车位
    2020-06-25 18:46:51:Thread-3抢到车位
    2020-06-25 18:46:51:Thread-5抢到车位
    2020-06-25 18:46:51:Thread-4抢到车位
    2020-06-25 18:46:54:Thread-3释放车位
    2020-06-25 18:46:54:Thread-5释放车位
    2020-06-25 18:46:54:Thread-6抢到车位
    2020-06-25 18:46:54:Thread-4释放车位
    2020-06-25 18:46:57:Thread-6释放车位

    3.2 Semaphore原理

    3.2.1 构造方法

    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    看到这里我想不用我继续往下追代码大家也能猜出来构造方法干啥的了,没错,就是设置AQS的state的值

    NonfairSync(int permits) {
        super(permits);
    }
    Sync(int permits) {
        setState(permits);
    }

    3.2.2 acquire方法

    acquire方法很简单,就是把可用资源数(state变量)-1。如果剩余资源数>=0则直接运行,否则进入线程等待队列

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    不废话,老知识,直接看tryAcquireShared方法在Semaphore中的实现

    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
    
    final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
            int available = getState();
            // 这里减去可用资源数
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                // 返回剩余资源数
                return remaining;
        }
    }

    3.2.3 release方法

    release方法很简单,就是把可用资源数(state变量)+1

    public void release() {
        sync.releaseShared(1);
    }
    

    tryReleaseShared在Semaphore的实现

    protected final boolean tryReleaseShared(int releases) {
        for (;;) {
            int current = getState();
            // 加上可用资源数
            int next = current + releases;
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            if (compareAndSetState(current, next))
                return true;
        }
    }

     

    展开全文
  • 常用方法: 1.countDown 工人干完了调用这个方法 2.await 老板分完活后,在等待检查,当CountDownLatch值为0时,则老板开始检查 二:Semaphore 使用场景:用于做限流处理,比如说同时只允许

    控制并发流程是指让各个线程之间互相协调,具体说就是一个线程等到其它事件或线程运行完毕达到要求。

    一:CountDownLach 类 使用场景:一个线程等待其他一个或多个线程执行完后再继续它的操作

    例如:举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查

    常用方法:

    1.countDown 工人干完了调用这个方法

    2.await 老板分完活后,在等待检查,当CountDownLatch的值为0时,则老板开始检查

    二:Semaphore 使用场景:用于做限流处理,比如说同时只允许5五个人访问,超过五个人访问就需要等待,类似这样的需求,下面的案例可以看出执行是五个五个的执行,等上一个五个执行完了,才会执行下一个

    常用方法:

    1.acquire();获取许可

    2.semp.release();访问完后,释放

    三:Condition 使用场景:当线程1需要等待某个条件的时候,它就去执行condition.await()方法,一旦执行了await()方法,线程就会进入阻塞状态。然后通常会有另外一个线程,假如是线程2吗,去执行对应的条件,知道这个条件达成的时候,线程2就会去执行condition.signal()方法,这时jvm就会从阻塞的线程里找,找到那些等待该condition的线程,当线程1就会收到可执行信号的时候,它的线程状态就会变成Runnable可执行状态

    常用方法:

    1.await 等待

    2.signal 唤醒 (signal是公平的,如果有多个线程等待,只会唤醒等待时间最长的线程)

    3.signalAll 会唤起所有正在等待的线程

    四:CycliBarrier 使用场景:5个人约玩,所有人都到场了,大家统一出发

    常用方法:

    1.await 等待

    与CountDownLatch区别

    1.作用不同:CycliBarrier要等固定数量的线程都到达了栅栏位置才能继续执行,而CountDownLatch只需等到数字是0,也就是说,CountDownLatdch用于事件,CycliBarrier用于线程

    2.可重用性不同:CountDownLatch在倒数到0并触发门闩打开后,就不能再次使用了,除非新建新的实例;而CycliBarrier可以重复使用

    五:总结

    1.相互等待,使用CountDownLatch

    2,控制并发总量,使用Semaphore

    展开全文
  • 写在前面◆ ◆ ◆◆并行程序开发将不可避免地要涉及多线程、多任务间写作和数据共享等问题。在JDK中,提供了多种途径实现多线程间的并发控制常用的方法有:内部锁、重入锁、读写锁、信号量...
  • 一、并发控制 原因:在多用户环境中,在同一时间可能会有多个用户更新相同记录,这会产生冲突。这就是著名并发性问题。 实现:最常用的处理多用户并发访问的方法是加锁。 当一个用户锁住数据库中某个对象时...
  • 在驱动程序中,当多个线程同时访问相同的资源时,可能会引发\"竞态\",因此我们必须对共享资源进行并发控制...Linux内核中解决并发控制的常用方法是自旋锁与信号量。本文详细介绍了自旋锁与信号量的特点和实现方法。
  • 4.4 并发控制方法  并行程序开发将不可避免地要涉及多线程,多任务间协作和数据共享等问题。在JDK中,提供了多种途径实现多线程间的并发控制常用的方法有:内部锁,重入锁,读写锁,信号量等。  4.4.1 Java...
  • 本文的并发控制是基于SQL Server提供并发机制控制,使用timestamp类型字段进行数据更新检测,这种机制要求在程序端修改数据后,要重新获取数据对象。 如果界面采用简单修改数据后,重新获取所有数据,再...
  • 上篇对多线程设计模式做了简单讲解,本篇我们将从:JDK多任务执行框架、JDK并发数据结构、JDK并发控制方法、锁性能和优化、无锁并行计算、协程等6方面汇总并发编程技术点,让小伙伴学习有个总体脉络。...
  • 设备驱动中的并发控制 ...解决并发控制的常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。  自旋锁与信号量“类似而不类”,类似说的是它们功能上的相似性,“不类”指代它们在 本质和实现机理上
  • 项目中常用的java并发操作一、java8新特性java并发流操作(结合纳姆达表达式)List list = new ArrayList<>();list..stream().parallel().forEach(list1 ->{// 调用方法 method});注:其中list1为list一个...
  • 在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的共享资源),可能会引发\"竞态\",因此...Linux内核中解决并发控制的常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。
  • Java并发控制机制

    千次阅读 2016-10-08 17:16:42
    在一般性开发中,笔者经常看到很多同学在对待java并发开发模型中只会使用一些基础的方法。比如volatile,...在JDK中,提供了多种途径实现多线程间的并发控制。比如常用的:内部锁、重入锁、读写锁和信号量。
  • Linux内核中解决并发控制的常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。 自旋锁与信号量"类似而不类",类似说的是它们功能上的相似性,"不类"指代它们在本质和实现机理上完全不一样,不属于一类。 ...
  • 4.设备驱动中的并发控制 在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的...Linux内核中解决并发控制的常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。 自旋锁与信...
  • 前言在我们的程序开发过程中,如果涉及到多线程环境,那么对于集合框架的使用就必须更加谨慎了,因为大部分的集合类在不施加额外控制的情况下直接在并发环境中直接使用可能会出现数据不一致的问题,所以为了解决这个...
  • 并发编程常用

    2018-04-09 17:57:56
    Semaphore:synchronized关键字加强版,主要用来控制线程并发的数量(permits)。类发放许可方式使减法操作,主要方法:acquire(permits),release(permits)。availablePermits()返回可用permits。drainPermits()...
  • 前言在我们的程序开发过程中,如果涉及到多线程环境,那么对于集合框架的使用就必须更加谨慎了,因为大部分的集合类在不施加额外控制的情况下直接在并发环境中直接使用可能会出现数据不一致的问题,所以为了解决这个...
  • 【转】深入浅出Linux设备驱动并发控制介绍 (2007-05...Linux内核中解决并发控制的常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。 自旋锁与信号量'类似而不类',类似说的是它们功能上的相似性,'不类'...
  • 前言在我们的程序开发过程中,如果涉及到多线程环境,那么对于集合框架的使用就必须更加谨慎了,因为大部分的集合类在不施加额外控制的情况下直接在并发环境中直接使用可能会出现数据不一致的问题,所以为了解决这个...
  • 在我们的程序开发过程中,如果涉及到多线程环境,那么对于集合框架的使用就必须更加谨慎了,因为大部分的集合类在不施加额外控制的情况下直接在并发环境中直接使用可能会出现数据不一致的问题,所以为了解决这个潜在...
  • 浅谈js中多并发的一些处理方法

    千次阅读 2017-09-28 10:05:43
    经常在写代码时候碰到这样场景:页面初始化时显示loading页,同时启动多个ajax并发请求获取数据,当每个...要实现这个场景容易碰到一个问题就是多并发怎么控制?下面是一些解决方法和思路: 并行改为串行

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 660
精华内容 264
关键字:

并发控制的常用方法