线程不安全类->线程安全的类->并发容器J.U.C

先检查再执行,必须保证原子性 :if(condition(a)){ handle(a);}

StringBuilder ->StringBuffer

SimpleDateFormat -> JodaTime

ArrayList,HashSet,HashMap等Collections

ArrayList  ->  Vector,Stack

HashMap  -> HashTable(Key,Value不能为null)

Collections.synchronizedXXX(List,Set,Map)

==============并发容器================

ArrayList  ->  CopyOnWriteArrayList

适合读多写少的场景 

读在原数组上读,不需要加锁

CopyOnWriteArrayList 的 设计思想

1、读写分离  2、最终一致性 3、使用时另外开辟空间,解决并发冲突

--------------------------------------------------------------------------------------------------

HashSet ,TreeSet   ->CopyOnWriteArraySet ,ConcurrentSkipListSet

HashMap,TreeMap -> ConcurrentHashMap,ConcurrentSkipListMap

 

 

安全共享对象策略--总结

线程控制:一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改

共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它

线程安全对象:一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通共公共接口随意访问它

被守护对象:被守护对象只能通过获取特定的锁来访问

 

=============================================================================

 

 

AbstractQueuedSynchronizer  --AQS

子类通过继承并通过实现它的方法管理其状态(acquire和release)的方法操纵状态

可以同时实现排它锁和共享锁模式(独占,共享)

 

AQS同步组件

CountDownLatch


package com.example.concurrency.example.aqs;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
* 用final修饰变量是明确不会被调整
*  latch.await();
* 可以给定等待时间 latch.await(10, TimeUnit.MILLISECONDS);
* 先打印finish,再执行启动的线程
* service.shutdown() 此方法并不会一调用所有的线程立即停止执行
* 它会把启动的线程依次执行完,再关闭
*/
public class CountDownLatchExample1 {

    public static final int threadCount = 100;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        final CountDownLatch latch = new CountDownLatch(threadCount);
        for(int i=0;i<threadCount;i++){
            final int threadnum = i;
            service.execute(() -> {
                try {
                    test(threadnum);
                } catch (InterruptedException e) {
                    System.out.println(e.getMessage());
                }finally {
                    latch.countDown();
                }
            });
        }
        latch.await(10, TimeUnit.MILLISECONDS);
        System.out.println("finish");
        service.shutdown();
    }

    private static void test(int i) throws InterruptedException {
        Thread.sleep(100);
        System.out.println(i);
    }

}

Semaphore 仅能提供有限访问的资源 如数据库的访问

 

package com.example.concurrency.example.aqs;

import java.util.concurrent.*;


public class SemaphoreExample {

    public static final int threadCount = 100;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        final CountDownLatch latch = new CountDownLatch(threadCount);
        final Semaphore semaphore = new Semaphore(20);
        for(int i=0;i<threadCount;i++){
            final int threadnum = i;
            service.execute(() -> {
                try {
                  //也可以同时获取多个许可和释放多个许可。那样就相当于单线程了
                    semaphore.acquire();//获取一个许可
                    test(threadnum);
                    semaphore.release();//释放一个许可

/* if(semaphore.tryAcquire()) {//尝试获取一个许可,获取不到就不执行
     test(threadnum);
     semaphore.release();//释放一个许可
 }else {
     System.out.println("丢弃");
 }*/
                } catch (InterruptedException e) {
                    System.out.println(e.getMessage());
                }finally {
                    latch.countDown();
                }
            });
        }
        latch.await(10, TimeUnit.MILLISECONDS);
        System.out.println("finish");
        service.shutdown();
    }

    private static void test(int i) throws InterruptedException {
        Thread.sleep(100);
        System.out.println(i);
    }

}

CyclicBarrier

public class CyclicBarrierExample2 {
    static CyclicBarrier barrier = new CyclicBarrier(5);
    public static void main(String[] args) throws InterruptedException {

        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int threadNum = i;
            Thread.sleep(1000);
            service.execute(() -> {
                try {
                    race(threadNum);
                } catch (Exception e) {
                    System.out.println("exception");
                }
            });
        }
        service.shutdown();
    }

    private static void race(int i) throws Exception {
        Thread.sleep(1000);
        System.out.println(i + " is ready");
        //尽可能多的捕获一些异常,捕捉完异常并不会影响后续代码的执行
        try {
            barrier.await(2000, TimeUnit.MILLISECONDS);//支持等待时间
        }catch (InterruptedException | TimeoutException |BrokenBarrierException e){
            System.out.println(i+" exception");
        }
        System.out.println(i+" is continue");
    }

}

AQS同步组件

ReentrantLock

ReenTrantLock(可重入锁)和synchronized区别

1)可重入性

2)锁的实现

3)性能的区别

4)功能区别

ReenTrantLock 独有的功能

1)可指定是公平锁还是非公平锁

提供了一个Condition类,可以分组唤醒需要唤醒的线程

提供能够中断等待锁的线程的机制 lock.lockInterruptibly()

 

ReentrantLock

@ThreadSafe
public class LockExample {

    public static int threadTotal=200;
    public static final int clientTotal = 5000;
    public static int count = 0;
    public static Lock lock = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        final ExecutorService service = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        CountDownLatch latch = new CountDownLatch(clientTotal);

        for(int i=0;i<clientTotal;i++){
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        add();
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        latch.countDown();
                    }

                }
            });
        }
        latch.await();
        service.shutdown();
        System.out.println(count);
    }

    public static void add(){
        lock.lock();
        try {
            count++;
        }finally {
            lock.unlock();
        }
    }

}

ReentrantReadWriteLock

@ThreadSafe
public class LockExample1 {

    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();
    private final Map<String, Data> map = new TreeMap<>();

    public Data get(String key){
       readLock.lock();
       try{
           return map.get(key);
       }finally {
           readLock.unlock();
       }
    }

    public Set<String> getAllKeys(){
        readLock.lock();
        try{
            return map.keySet();
        }finally {
            readLock.unlock();
        }
    }

    public Data put(String key,Data data){
        writeLock.lock();
        try{
           return map.put(key,data);
        }finally {
            writeLock.unlock();
        }
    }

    class Data {

    }
}

StampedLock

@ThreadSafe
public class LockExample2 {
    class Point {
        private double x, y;
        private final StampedLock sl = new StampedLock();

        void move(double deltaX, double deltaY) { // an exclusively locked method
            long stamp = sl.writeLock();
            try {
                x += deltaX;
                y += deltaY;
            } finally {
                sl.unlockWrite(stamp);
            }
        }

        /**
         * 乐观读锁案例
         * @return
         */
        double distanceFromOrigin() { // A read-only method
            long stamp = sl.tryOptimisticRead();//获得一个乐观读锁
            double currentX = x, currentY = y;//将两个字段读入本地局部变量
            if (!sl.validate(stamp)) {//检查发出乐观读锁后,同时是否有其他写锁发生
                stamp = sl.readLock();//如果没有,我们再次获得一个读悲观锁
                try {
                    currentX = x;//将两个字段读入本地局部变量
                    currentY = y;//将两个字段读入本地局部变量
                } finally {
                    sl.unlockRead(stamp);
                }
            }
            return Math.sqrt(currentX * currentX + currentY * currentY);
        }

        /**
         * 悲观读锁案例
         * @param newX
         * @param newY
         */
        void moveIfAtOrigin(double newX, double newY) { // upgrade
            // Could instead start with optimistic, not read mode
            long stamp = sl.readLock();
            try {
                while (x == 0.0 && y == 0.0) {//循环,检查当前状态是否符合
                    long ws = sl.tryConvertToWriteLock(stamp);//将读锁转为写锁
                    if (ws != 0L) {//这是确认转为写锁是否成功
                        stamp = ws;//如果成功,替换票据
                        x = newX;//进行状态改变
                        y = newY;//进行状态改变
                        break;
                    } else {//如果不能成功转换为写锁
                        sl.unlockRead(stamp);//我们显示释放读锁
                        stamp = sl.writeLock();//显示直接进行写锁  然后再通过循环再试
                    }
                }
            } finally {
                sl.unlock(stamp);//释放读锁或写锁
            }
        }
    }
}

Condition

public class LockExample4 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        new Thread() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    System.out.println("wait single");
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("get a single");
                lock.unlock();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("get lock");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                condition.signalAll();
                System.out.println("send single");
                lock.unlock();
            }
        }.start();
    }
}

FutureTask

Callable与Runnable接口对比

Future接口

FutureTask类

 

Future

public class FutureExample {
   static class MyCallable implements Callable<String>{

        @Override
        public String call() throws Exception {
            System.out.println("do sth");
            Thread.sleep(5000);
            return "done";
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        Future<String> future = service.submit(new MyCallable());
        System.out.println("do sth in main");
        Thread.sleep(1000);
        String result = future.get();
        System.out.println(result);
    }

}

FutrueTask

public class FutureTaskExample {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("do sth in call");
                Thread.sleep(5000);
                return ("done");
            }
        });
        new Thread(futureTask).start();
        System.out.println("do sth in main");
        Thread.sleep(1000);
        String result = futureTask.get();
        System.out.println(result);
    }
}

ForkJoin框架 ====待学习 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值