JUC学习笔记

下面的学习笔记参考狂神说java的博客


线程和进程

进程:一个程序,QQ.exe Music.exe 程序的集合

一个进程往往可以包含多个线程,至少包含1个线程

java默认有几个线程? 2个mian,GC

线程:开了一个进程 Typora,写字,自动保存(线程负责的)

对于Java而言 Thread,Runnable,Callable

java真的可以开启线程吗?  开不了的

java无法直接操作硬件

并发,并行

并发(多线程操作同一资源)

>CPU1核,模拟出多条线程,天下武功,唯快不破,快速交替

并行(多个人一起行动)

>CPU 多核,多个线程可以同时执行.线程池

并发编程的本质:充分利用CPU的资源

所有的公司都很看重

企业,挣钱=>提高效率,裁员

人员(减),技术成本(提高)

线程有几个状态

NEW  新生

RUNNABLE 运行

WAITING 等待

TIMED_WAITING  超时等待

TERMINATED 终止

wait/sleep 区别

1.来自不同的类

wait=> Object

sleep=> Thread

2.关于锁的释放

wait会释放锁,sleep睡觉了,抱着锁睡觉,不会释放!

3.使用的范围是不同的

wait:必须再同步代码块中

sleep可以再任何地方睡

4.是否需要捕获异常

wait不需要捕获异常

sleep必须捕获异常


3.Lock锁(重点)

公平锁:十分公平:可以先来后到

非公平锁:十分不公平:可以插队  (默认)

Synchronized 和 Lock 区别

1.Synchronized 内置的java关键字,Lock是一个java类

2.Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁

3.Synchronized 会自动释放锁,lock必须要手动释放锁! 如果不释放锁,会死锁

4.Synchronized 线程 1 (获得锁,阻塞),线程2(等待,傻傻的等) Lock锁就不一定会一直等待

5.Synchronized 可重入锁,不可以中断,非公平,Lock 可重入锁,可以判断锁,非公平(可设置公平)

6.Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码

是什么,任何判断锁的是谁!

4.生产者和消费者问题

通过Lock 找到Condion


5.8锁现象

如何判断锁的是谁?永远的知道什么是锁,锁到底锁的是谁!

1.两个同步方法,都没延迟,就是先来后到

2. 两个同步方法,对第一个增加延迟并不会改变执行顺序,排队

3. 同时执行 一个普通方法,和一个同步方法,先来后到,再比较谁延迟谁后发出,不排队

4. 两个对象分别执行一个方法,这两个同时执行,所以延迟的会后面发出,不排队

5.一个对象 同时执行两个静态同步方法,延迟的还是会先执行,要排队

6.两个对象,分别执行两个静态同步方法,延迟的还是会先执行,要排队(虽然两个对象,但是还是要排队)

7.1个对象,执行一个静态带延迟的同步和一个普通同步,普通同步先执行(不排队)

8.2个对象,分别执行个静态带延迟的同步和一个普通同步,普通同步先执行(不排队)

小结:

new this 具体的一个手机

static Class 唯一的一个模板

同步方法加了一个static后,他就像一个新的对象,只和且一定加static的比较


集合类不安全

List多线程不安全

 //并发下 ArrayList 不安全
        /**
         * 解决方案:
         * 1.List<String> list=new Vector<>();
         * 2.List<String> list= Collections.synchronizedList(new ArrayList<>());
         * 3.List<String> list= new CopyOnWriteArrayList<>();
         *
         */
        //CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略
        //多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
        //在写入的时候避免覆盖,造成数据问题

        //读写分离 MyCat
        //CopyOnWriteArrayList 比Vector 牛在哪里
        //CopyOnWriteArrayList底层使用lock Vector在多线程的时候synchronized,效率低

        List<String> list= new CopyOnWriteArrayList<>();
        for(int i=0;i<=10;i++){
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }

Set多线程不安全



        //Set<String> set=new HashSet<>();
        //HashSet的底层是HashMap
        //解决方案1:Set<String> set= Collections.synchronizedSet(new HashSet<>());
        //解决方案2:Set<String> set=new CopyOnWriteArraySet<>();
        Set<String> set=new CopyOnWriteArraySet<>();

        for(int i=1;i<=30;i++){
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }

hashSet的底层是HashMap

Map多线程不安全

        //map是这样用的么? 不是,工作中不用 HashMap
        // 默认等价于什么? new HashMap<>(16,0.75);
        //HashMap<String,String> map=new HashMap<>();
        Map<String,String> map=new ConcurrentHashMap<>();
        // 加载因子 ,初始化容量
        for(int i=1;i<=30;i++){
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }

Callable

Callable类似Runnable,Runnable不返回结果,也不能抛出异常

有缓存

结果可能需要等待,会阻塞

public class CallableTest {
    public static void main(String[] args) throws Exception{
        // new Thread(new Runnable()).start();
        // new Thread(new FutureTask<V>()).start();
        // new Thread(new FutureTask<V>( Callable )).start()

        new Thread().start();//怎么启动Callable

        MyThread thread=new MyThread();
        //适配类
        FutureTask futureTask=new FutureTask(thread);  //适配类

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start();//结果会被缓存,效率高

        Integer ov=(Integer) futureTask.get();//这个get方法 可能产生阻塞,把他放到最后一行

        System.out.println(ov);
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call(){
        System.out.println("call()");
        //耗时的操作
        return 1024;
    }
}

常用的辅助类

1.CountDownLatch

这个类使一个线程等待其他线程各自执行完毕后再执行(减法计数器)

public class CountDownLatchDemo {
    public static void main(String[] args) throws Exception{
        //倒计时是6,必须要执行任务的时候,再使用
        CountDownLatch  countDownLatch=new CountDownLatch(6);//如果为7,就会一直等待

        for(int i=1;i<=6;i++){
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"Go Out");
                countDownLatch.countDown();//数目-1
            },String.valueOf(i)).start();
        }

        countDownLatch.await();//等待计数器归零,然后再向下执行

        System.out.println("Close Door");

    }
}

2.CycliBarrier

它的作用就是会让所有线程都等待完成后才会继续下一步行动

public class CyclicBarrierDemo {
    public static void main(String[] args){
        /**
         * 集齐7颗龙珠召唤神龙
         */
        //召唤龙珠的线程
        CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{//如果 将7改为6,呢么在输出6.收集6个龙珠,就召唤神龙成功,然后再7,收集7个龙珠
            System.out.println("召唤神龙成功");                       //如果 将7改为8,呢么会一直等待
        });

        for(int i=1;i<=7;i++){
            final int temp= i;
            new Thread(()->{
                //lamdba能操作到i么
                System.out.println(Thread.currentThread().getName()+",收集"+temp+"个龙珠");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

3.Semaphore

Semaphore 是一个计数信号量,必须由获取它的线程释放。

常用于限制可以访问某些资源的线程数量,例如通过 Semaphore 限流

public class SemaphoreDemo {
    public static void main(String[] args) {
        //线程数目:停车位,限流!
        Semaphore  semaphore=new Semaphore(3);

        for(int i=1;i<=6;i++){
            new Thread(()->{
                //acquire() 得到
                try {
                    semaphore.acquire();//获取
                    System.out.println(Thread.currentThread().getName()+"抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally {
                    semaphore.release();//释放
                }
            },String.valueOf(i)).start();
        }
    }
}

读写锁

ReadWriteLock 读写锁

读的时候可以多个线程读,写的时候只能1个线程写

读写所允许同一时刻被多个读线程访问,但是在写线程访问时,所有的读线程和其他的写线程都会被阻塞

/**
 * 独占锁(写锁) 一个只能被一个线程占有
 * 共享锁(读锁) 多好线程可以同时占有
 * 读-读 可以共存!
 * 读-写 不能共存!
 * 写-写 不能共存!
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        
        MyCache myCache=new MyCache();
        MyCacheLock myCacheLock=new MyCacheLock();

        //写入
        for(int i=1;i<=10;i++){
            final int temp=i;
            new Thread(()->{
                myCacheLock.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        //读取
        for(int i=1;i<=10;i++){
            final int temp=i;
            new Thread(()->{
                myCacheLock.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}

class MyCacheLock{
    private volatile Map<String,Object> map=new HashMap<>();
    //读写锁,更加细粒度的控制
    private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();

    //存,写入的时候,只希望同时只要一个线程写
    public void put(String key,Object value){
        readWriteLock.writeLock().lock();//写锁
        try {
            System.out.println(Thread.currentThread().getName()+"写入"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"写入OK");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            readWriteLock.writeLock().unlock();
        }
    }

    //取,读,所以人都可以读
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取"+key);
            Object o=map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取OK");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            readWriteLock.readLock().unlock();
        }
    }
}

阻塞队列 BlockingQueue

方式抛出异常有返回值阻塞超时等待
添加add()offer()put()offer(,,)
移除remove()poll()take()poll(,)
检测队首element()peek()--

 

 

 

 

 

    public static void main(String[] args) throws Exception{
        //Collection:  {List,SetBlockingQueue}
        test4();
    }

    public static void test1(){
        //需要写队列的大小
        ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));

        //抛出异常: java.lang.IllegalStateException: Queue full
        //System.out.println(blockingQueue.add("d"));
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
    }

    public static void test2(){
        ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        System.out.println(blockingQueue.offer("d"));

        System.out.println(blockingQueue.peek());

        System.out.println(blockingQueue.element());

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
    }

    public static void test3() throws InterruptedException{
        /**
         * 等待,阻塞(一直阻塞)
         */
        ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue<>(3);

        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        //blockingQueue.put("d");//队列没有位置,会一直等待
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());//没有元素,会一直等待
    }

    public static void test4() throws InterruptedException{
        /**
         * 等待,阻塞(等待超时)
         */
        ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3);

        System.out.println("1");
        arrayBlockingQueue.offer("a");
        arrayBlockingQueue.offer("b");
        arrayBlockingQueue.offer("c");
        arrayBlockingQueue.offer("d",2, TimeUnit.SECONDS);//阻塞,等待2秒就退出

        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll(2,TimeUnit.SECONDS));

        System.out.println("3");
    }

同步队列 SynchronousQueue

/**
 * 同步队列
 * 容量为1,同时只能存在一个
 */
public class SynchronousQueueDemo {
    public static void main(String[] args) {

        SynchronousQueue<String> synchronousQueue=new SynchronousQueue<String>();//同步队列

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+" put 1");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName()+" put 2");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName()+" put 3");
                synchronousQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+" => "+synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+" => "+synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+" => "+synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"B").start();
    }
}

 


线程池 

池化技术

程序的运行,本质:占用系统的资源!优化资源的使用! => 池化技术

线程池,连接池,内存池,对象池..........

池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完还给我.

线程池的好处:

1.降低资源的消耗

2.提高响应的速度

3.方便管理

线程复用,可以控制最大并发数,管理线程

线程池:{三大方法,7大参数,4种拒绝策略}

三大方法:

// Executors 工具类:3大方法
//使用线程池之后,要使用线程池 创建线程
public class Demo1 {
    public static void main(String[] args) {

        //ExecutorService threadPool=Executors.newSingleThreadExecutor(); //单个线程

        ExecutorService threadPool=Executors.newFixedThreadPool(5);   //创建固定的线程池的大小

        //ExecutorService threadPool=Executors.newCachedThreadPool();//创建一个可伸缩的线程池

        try {
            for(int i=0;i<10;i++){
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }
        }finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//21亿
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

三个方法均调用了ExecutorService

7大参数

    public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
                              int maximumPoolSize,//最大核心线程池大小
                              long keepAliveTime,//超时了没有调用就释放
                              TimeUnit unit,//超时单位
                              BlockingQueue<Runnable> workQueue,//阻塞队列
                              ThreadFactory threadFactory,//线程工厂,一般不用动
                              RejectedExecutionHandler handler) {//拒绝策略
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,避免资源耗尽的奉献

手动创建一个线程池

// Executors 工具类:3大方法
//使用线程池之后,要使用线程池 创建线程

/**
 * ExecutorService threadPool=Executors.newSingleThreadExecutor(); //单个线程
 * ExecutorService threadPool=Executors.newFixedThreadPool(3);//创建固定的线程池的大小
 * ExecutorService threadPool=Executors.newCachedThreadPool();//创建一个可伸缩的线程池
 */
public class Demo1 {
    public static void main(String[] args) {
        //自定义线程池! 工作 ThreadPoolExecutor

        int maxCPU=Runtime.getRuntime().availableProcessors();//获取cpu的线程数

        // 最大线程到底该如何定义
        // 1.CPU密集型 ,几核就定义为几,保持cpu效率最高
        // 2.IO密集型 判断你的任务中十分耗IO的线程
        ExecutorService threadPool=new ThreadPoolExecutor(
                2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                //new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,不处理这个人,抛出异常
                //new ThreadPoolExecutor.CallerRunsPolicy());//只要线程池未关闭,该策略直接在调用者线程中运行当前被丢弃的任务
                //new ThreadPoolExecutor.DiscardPolicy());//队列满了,不允许多的任务,丢掉多的任务
                new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,丢掉任务,不会抛出异常,
        try {
            //最大承载数:BlockingDeque +max

            for(int i=1;i<=9;i++){
                //使用线程池创建线程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }
        }finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

4种拒绝策略

new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,不处理这个人,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy());//只要线程池未关闭,该策略直接在调用者线程中运行当前被丢弃的任务
new ThreadPoolExecutor.DiscardPolicy());//队列满了,不允许多的任务,丢掉多的任务
new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,丢掉任务,不会抛出异常,

线程池最大的大小该如何去设置? => IO密集型,cpu密集型 :(调优)


四大函数式接口

新时代的程序员必会:lambda表达式,链式编程,函数式接口,Stream流式计算

函数式接口:只有一个方法的接口

@FunctionalInterface public interface Runnable {   public abstract void run(); } 
// 泛型、枚举、反射 
// lambda表达式、链式编程、函数式接口、Stream流式计算 
// 超级多FunctionalInterface 
// 简化编程模型,在新版本的框架底层大量应用! 
// foreach(消费者类的函数式接口)

Function函数式接口

/**
 * Function 函数式接口,只有一个输入参数,有一个输出
 * 只要是 函数型接口 可以 用 lambda表达式简化
 */
public class Demo01 {
    public static void main(String[] args) {

        //工具类:输出输入的值
        Function function=new Function<String,String>() {
            @Override
            public String apply(String str) {
                return str;
            }
        };

        Function function1=(str)->{return str;};//用 lambda表达式简化 和上面的等级

        System.out.println(((Function<String, String>) function).apply("aaa"));

        System.out.println(function1.apply("bbb"));

    }
}
predicate函数式接口
/**
 * 断定型接口: 有一个输入参数,返回值只能是 布尔值
 */
public class Demo02 {
    public static void main(String[] args) {

        //判断字符串是否为空
        Predicate<String> predicate=new Predicate<String>() {
            @Override
            public boolean test(String str) {
                return str.isEmpty();
            }
        };

        System.out.println(predicate.test(""));

        Predicate<String> predicate1=(str)->{return str.isEmpty();};

    }
}

Consumer 消费型接口

/**
 * 消费型接口
 * 只有输入,没有返回值
 */
public class Demo03 {
    public static void main(String[] args) {
        Consumer<String> consumer=new Consumer<String>() {
            @Override
            public void accept(String str) {
                System.out.println(str);
            }
        };

        Consumer<String> consumer1=(str)->{
            System.out.println(str);
        };

        consumer1.accept("gg");

    }
}

Supplier 供给型接口

/**
 * 供给型接口
 * 没有参数,只有返回值
 */
public class Demo04 {
    public static void main(String[] args) {

        Supplier<Integer> supplier=new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 1024;
            }
        };

        Supplier<Integer> supplier1=()->{return 1024;};

        System.out.println(supplier1.get());

    }
}

Stream流式计算

什么是Stream流式计算?

大数据存储+计算

存储:集合,MySQL 本质就是存储

计算都应该交给流操作!

/**
 * 题目要求:只用一行代码实现
 * 1.ID必须为偶数
 * 2.年龄必须大于23
 * 3.用户名转化为大写字母
 * 4.用户名字母倒着排序
 * 5.只输出一个用户!
 */

public class Test {
    public static void main(String[] args) {
        User user1=new User(1,"a",21);
        User user2=new User(2,"b",22);
        User user3=new User(3,"c",23);
        User user4=new User(4,"d",24);
        User user5=new User(5,"e",25);

        List<User> list= Arrays.asList(user1,user2,user3,user4,user5);

        //Stream流,链式编程,函数式接口
        list.stream()
                .filter(u->{return u.getId()%2==0;})
                .filter(u->{return u.getAge()>23;})
                .map(u->{return u.getName().toUpperCase();})
                .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
                .limit(1)
                .forEach(System.out::println);
    }
}

ForkJoin

ForkJoin在JDK 1.7 并行执行任务!提高效率,大数据量

ForkJoin特点:工作窃取(这里维护了一个双端队列)

/**
 * 求和计算
 * 如何使用forkjoin
 * 1.forkjoinPool 通过他来执行
 * 2.计算任务 forkjoinpool.execute(ForkjoinTask task)
 * 3.计算类继承ForkjoinTask
 */
public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start;
    private Long end;

    private Long temp=10000L;

    public ForkJoinDemo(Long start,Long end){
        this.start=start;
        this.end=end;
    }

    public static void main(String[] args) {

    }

    @Override
    protected Long compute(){
        if(end-start<temp){//用分支合并计算
            Long sum=0L;
            for(Long i=start;i<=end;i++){
                sum+=i;
            }
            return sum;
        }else{//很像递归
            long mid=(start+end)/2;//中间值
            ForkJoinDemo task1=new ForkJoinDemo(start,mid);
            task1.fork();//拆分任务,把任务压入线程队列
            ForkJoinDemo task2=new ForkJoinDemo(mid+1,end);
            task2.fork();
            return task1.join()+task2.join();
        }
    }
}

测试:

public class Test {
    public static void main(String[] args) throws Exception{
        test3();
    }

    public static void test1(){
        long start=System.currentTimeMillis();
        Long sum=0L;
        for (Long i=1L;i<=10_0000_0000;i++){
            sum+=i;
        }
        long end=System.currentTimeMillis();
        System.out.println("sum="+sum+",时间:"+(end-start));
    }

    public static void test2() throws Exception{//快百分之10几
        long start=System.currentTimeMillis();
        Long sum=0L;

        ForkJoinPool forkJoinPool=new ForkJoinPool();
        ForkJoinTask<Long> task=new ForkJoinDemo(0L,10_0000_0000L);
        ForkJoinTask<Long> submit=forkJoinPool.submit(task);

        sum=submit.get();

        long end=System.currentTimeMillis();
        System.out.println("sum="+sum+",时间:"+(end-start));

    }

    public static void test3(){//块几十倍
        long start=System.currentTimeMillis();
        Long sum=0L;
        //Stream 并行流()

        sum=LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0,Long::sum);

        long end=System.currentTimeMillis();
        System.out.println("sum="+sum+",时间:"+(end-start));
    }
}

JMM

volatile是java虚拟机提供的轻量级的同步机制

1.保证可见性

2.不保证原子性

3.禁止指令重排

什么是jMM?

java内存模型,不存在的东西,概念!约定!

关于JMM的一些同步的约定:

1.线程解锁前,必须把共享变量立刻刷回主存

2.线程加锁前,必须读取主存中的最新值到工作内存中

3.加锁和解锁是同一把锁

线程 工作内存,主内存

8种操作

指令重排

什么是指令重排:你写的程序,计算机并不是按照你写的那样去执行的.

源代码...->编译器优化重排...->指令并行也可能重排...->内存系统也会重排...->执行

int x=1; //1
int y=2; //2
x=x+5;   //3
y=x*x;   //4

volatile可以避免指令重排

内存屏障,cpu指令,作用

1.保证特定的操作的执行顺序

2.可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)

Volatile是可以保证可见性,不能保证原子性,由于内存屏障,可以避免指令重排


单例模式


各种锁的理解

公平锁和非公平锁

公平锁:非常公平,不能插入,必须按顺序执行

非公平锁:非常不公平,可以插队(默认是公平的)

可重入锁

自旋锁

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环

public class SpinlockDemo {
    //int 0
    //Thread null
    AtomicReference<Thread> atomicReference=new AtomicReference<>();

    public void myLock(){
        Thread thread=Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"==>  mylock");

        //自旋锁
        while(!atomicReference.compareAndSet(null,thread)){

        }
    }

    public void myUnLock(){
        Thread thread=Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"==>  myUnlock");
        atomicReference.compareAndSet(thread,null);
    }
}

测试:

public class TestSpinLock {
    public static void main(String[] args) throws Exception{

        ReentrantLock reentrantLock=new ReentrantLock();
        reentrantLock.lock();
        reentrantLock.unlock();

        //底层使用自旋锁
        SpinlockDemo lock=new SpinlockDemo();

        new Thread(()->{
            lock.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.myUnLock();
            }
        },"T1").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            lock.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.myUnLock();
            }
        },"T2").start();
    }
}

死锁

两个锁互相争抢

public class DeadLockDemo {
    public static void main(String[] args) {

        String lockA="lockA";
        String lockB="lockB";

        //A想获取B,B又想获取A,造成死锁
        new Thread(new MyThread(lockA,lockB),"A").start();
        new Thread(new MyThread(lockB,lockA),"B").start();

    }
}

class MyThread implements Runnable{

    private String lockA;
    private String lockB;

    public MyThread(String lockA,String lockB){
        this.lockB=lockB;
        this.lockA=lockA;
    }

    @Override
    public void run(){

        synchronized (lockA){
            System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>get"+lockB);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA);
            }
        }
    }
}

排查死锁:

使用Terminal 输入: jps -l  

查看当前的进程

然后输入:  jstack 进程号

可以看到是否有死锁,以及死锁在哪里产生

 

面试,工作中排查问题

1.日志

2.堆栈信息

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值