信号量Semaphore,AtomicInteger

 

countDownlunch:多线程阻塞控制,线程池所有线程执行完后,主线程继续执行
信号量Semaphore:多线程可同时使用资源控制
java.util.concurrent.CountDownLatch
java.util.concurrent.Semaphore
java.util.concurrent.locks.ReentrantLock
java.util.concurrent.atomic.AtomicInteger

 

首先在java层面,reentrantlock以及其他同步工具类,比如ConcurrentHashMap,CountDownLatch,CyclicBarrier,以及信号量 semaphore,在底层都是通过实现抽象类AbstractQueuedSynchronizer(AQS)来实现各种锁功能,比如乐观锁,悲观锁,互斥锁,共享锁,读写锁等,在java层面通过继承AQS,然后配合unsafe提供的CAS操作以及链表这个数据结构,去实现乐观锁,互斥,共享,自旋等锁,当需要阻塞线程的时候,通过unsafe类调用操作系统的mutex互斥锁去实现阻塞。

ReentrantLock
lock方法实现 AbstractQueuedSynchronizer.compareAndSetState unsafe.compareAndSwapInt

Semaphore
semp.acquire()方法实现 AbstractQueuedSynchronizer.acquireSharedInterruptibly compareAndSetState

 

 

 

首先要说一下,AtomicInteger类compareAndSet通过原子操作实现了CAS操作,最底层基于汇编语言实现。
简单说一下原子操作的概念,“原子”代表最小的单位,所以原子操作可以看做最小的执行单位,该操作在执行完毕前不会被任何其他任务或事件打断。
CAS是Compare And Set的一个简称,如下理解:
1,已知当前内存里面的值current和预期要修改成的值new传入
2,内存中AtomicInteger对象地址对应的真实值(因为有可能别修改)real与current对比,
相等表示real未被修改过,是“安全”的,将new赋给real结束然后返回;不相等说明real已经被修改,结束并重新执行1直到修改成功

   public  int incrementAndGetModulo(AtomicInteger ai) {
        for (;;) {
            int current = ai.get();
            System.out.println(Thread.currentThread().getName()+" currentBefore "+current);
            int next =(current+1) ;
            if (ai.compareAndSet(current, next)){
                System.out.println(Thread.currentThread().getName()+"********current:"+current+"next"+next);//compareAndSet 保存next,如果在执行过程中其他线程改变了current,则本次保存不成功,继续循环取值
                return (int)next;
            }
        }
    }

AtomicIntegerTest ait = new AtomicIntegerTest();
        AtomicInteger ai = new AtomicInteger();
        Thread t1 = new Thread(){
            public void run() {
                System.out.println("t1 "+Thread.currentThread().getName());
                int i = 0;
                while (i++ < 10)
                ait.incrementAndGetModulo(ai);
            }
        };
        Thread t2 = new Thread(){
            public void run() {
                System.out.println("t2 "+Thread.currentThread().getName());
                int i = 0;
                while (i++ < 10)
                    ait.incrementAndGetModulo(ai);
            }
        };
快速实现 int re = ai.getAndIncrement();//返回旧值(即加1前的原始值) 返回旧值(即加1前的原始值)

 

    public int getNum(AtomicInteger atomicInteger){
        while (true){
           int i = atomicInteger.get();
           int m = i+1;
           if(atomicInteger.compareAndSet(i,m)){
               return m;
           }
        }
    };

    public static void main(String[] args) {
        AtomicIntegerTest atomicIntegerTest = new AtomicIntegerTest();
        AtomicInteger atomicInteger = new AtomicInteger();
        for(int i=0;i<100;i++){
            System.out.println(atomicIntegerTest.getNum(atomicInteger));
        }
    }

  

 

 

 

 信号量Semaphore(如果一段业务只允许一个线程执行就可以把信号量设为1,当再启动一个线程时去获取信号量,当上一个线程执行完后会释放信号量,此时第二个线程就可以获取信号量进而执行代码,两个线程需公用同一个Semaphore实体)

package cn.com.xmh.test;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class TestClass {
    /**
    * 1,Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可
    * 2,如果是线程实现类中,Semaphore必须是静态的,所有线程共享一个Semaphore
     */
    public static void main(String[] args) {
        // 线程池
        ExecutorService exec = Executors.newCachedThreadPool();
        // 只能5个线程同时访问
        final Semaphore semp = new Semaphore(5);
        // 模拟20个客户端访问
        for (int index = 0; index < 20; index++) {
            final int NO = index;
            Runnable run = new Runnable() {
                public void run() {
                    //while(true){
                    String tname = Thread.currentThread().getName();
                    try {
                        // 获取许可
                        //System.out.println(tname+" --------acqueir before---------"+ semp.availablePermits());
                        semp.acquire();
                        Random random = new Random();
                        int i=random.nextInt(10);
                        System.out.println(tname+" Accessing: " + NO+"  sleep:"+i+" -----占用----"+ semp.availablePermits());
                        Thread.sleep((long) (i * 1000));
                        // 访问完后,释放
                        semp.release();
                        System.out.println(tname+" -------release----------"+ semp.availablePermits());//有可能刚释放就被阻塞的线程获取到信号,这里可用信号就为0
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //}
                }
            };
            exec.execute(run);
        }
        // 退出线程池
        exec.shutdown();//no new tasks will be accepted
    }

}

  

 

多线程
public class ThreadFirst extends Thread{
     private ThreadTest test;
     public ThreadFirst(ThreadTest tt) {
           this.test = tt;
     }
     public void run(){
           //while(true){
           test.test();
           //}
 
     }
 
}
public class ThreadSecond extends Thread{
     private ThreadTest test;
     public ThreadSecond(ThreadTest tt) {
           this.test = tt;
     }
     public void run(){
           //while(true){
           test.test();
           //}
 
     }
 
}
public class ThreadTest {
     public synchronized void test(){
           for(int i = 0; i < 10; i++){
                if(i == 5){
                     try {
                           this.wait();
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
                }else{
                     this.notifyAll();
                }
                System.out.println(Thread.currentThread().getName()+" "+i);
           }
     }  
}

  

 

posted @ 2020-04-05 17:38  苍天一穹  阅读(526)  评论(0)    收藏  举报