多线程JUC学习

补充之前的学习笔记

1JUC是什么

1.1 Java.util.concurrent =JUC

1.2 进程:系统里运行的多个程序QQ.exe     线程:一个进程中有多个线程

1.3 线程的多种状态。

.start()–就绪状态

State:

new创建  runnable启动  blocked阻塞 waiting等待(不见不散) timed_waiting等待(过时不候) terminated终结

1.4  wait交锁  sleep不交锁

1.5  并发:同一时间点多个线程访问同一个资源           并行:同时执行多个资源

 

2、lambda表达式

①写法:拷贝中括号+写死右箭头+落地大括号

②只有函数接口(接口里只有一个方法时)才能用lambda表达式

③接口上标记@FunctionalInterface

Foo foo = () -> {业务逻辑代码,实现方法}

④default方法的实现

用@FunctionalInterface的接口只能有个一方法,但是可以又多个default方法

⑤静态方法实现

用@FunctionalInterface的接口只能有个一方法,但是可以又多个default方法,可以有多个静态方法

 

3、线程间的通信

3.1生产者+消费者

3.2通知等待唤醒机制

判断   干活    通知

3.3 2个线程变4个线程,禁止出现虚假唤醒,判断条件用while

3.4  

—————-lock—————–   

Lock lock=new   ReentrantLock();

Condition condition = lock.newCondition();

condition.awati();    codittion.signalAll();           

——————-syncronised—————–    

          |                             |

      wait();                       notifiyAll();

 

4、传值和传引用

基本类型传复印件

引用类型传引用

String类型比较特殊,因为有个池的概念,所以相当于指向变了,但是原来的指针还是指向原来的引用

 

5、Callable

callable:有异常、有返回值、call

runnable:无异常、无返回值、run

FutureTask作用:异步调用

自顶向下,逐步求精

一个futuretask被多个线程调用,结果可以复用

futureTask.get()只允许放到最后,get方法只计算一次 

—————–原理,底层——————

①在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过future对象获得后台作业的计算结果或者执行状态。

②一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果

③仅再计算完成时才能检索结果,如果计算尚未完成,则阻塞get方法,一旦计算完成,就不能再重新开始或者取消计算,get方法获取结果只有再计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。

 

6、ReadWriteLock

ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock ();

rwLock .writeLock().lock();

rwLock .readLock().lock();

读写锁案例:读可共享,写排他

 

class ReadWrite{

      private Object obj;

      private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

      

      public void writeLock(Object obj){

             rwLock.writeLock().lock();

             try {

                   this. obj = obj;

                  System. out.println(Thread. currentThread().getName()+”写线程正在执行\t”+obj);

            } catch (Exception e) {

                   // TODO: handle exception

            } finally{

                   rwLock.writeLock().unlock();

            }

      }

      

      public void readLock(){

             rwLock.readLock().lock();

             try {

                  System. out.println(Thread. currentThread().getName()+”读线程正在执行\t”+obj);

            } catch (Exception e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

            } finally{

                   rwLock.readLock().unlock();

            }

      }

      

}

 

 

7、线程池

ExecutorService service=Executors.newFixedThreadPool(5);//一池5线程(核心线程=最大线程=5)

  • 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列;

  • 由于阻塞队列是一个无界队列,因此永远不可能拒绝任务;

  • 由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。

 

    public static ExecutorService newFixedThreadPool( int nThreads) {

        return new ThreadPoolExecutor( nThreads, nThreads ,

                                      0L, TimeUnit. MILLISECONDS,

                                      new LinkedBlockingQueue<Runnable>());

    }

ExecutorService service=Executors.newSingleThreadExecutor();//一池1线程(核心线程=最大线程=1)

 

 public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService

            ( new ThreadPoolExecutor(1, 1,

                                    0L, TimeUnit. MILLISECONDS,

                                    new LinkedBlockingQueue<Runnable>()));

    }

 

ExecutorService service=Executors.newCachedThreadPool();//一池N线程(核心线程0,最大线程int的最大值相当于没有上限)

  • 它是一个可以无限扩大的线程池;

  • 它比较适合处理执行时间比较小的任务;

  • corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;

  • keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;

  • 采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。

 

public static ExecutorService newCachedThreadPool () {

  return new ThreadPoolExecutor(0, Integer. MAX_VALUE,

                                      60L, TimeUnit. SECONDS,

                                      new SynchronousQueue<Runnable>());

}

 

service.submit(Runnable);

service.shutdown();

———————————

ScheduledExecutorService service=Executors.newScheduledThreadPool(5);//时间轮询,每隔多少时间执行一个任务,如果线程忙不过来会自动新加线程(核心线程5,最大线程int最大值相当于没有上限)

  • 它采用DelayQueue存储等待的任务

  • DelayQueue内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序;

  • DelayQueue也是一个无界队列;

  • 工作线程的执行过程:

  • 工作线程会从DelayQueue取已经到期的任务去执行;

  • 执行结束后重新设置任务的到期时间,再次放回DelayQueue

 

     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {

        return new ScheduledThreadPoolExecutor( corePoolSize);

     }

    public ScheduledThreadPoolExecutor( int corePoolSize) {

        super(corePoolSize, Integer. MAX_VALUE, 0, TimeUnit. NANOSECONDS,

              new DelayedWorkQueue());

     }

     public ThreadPoolExecutor( int corePoolSize,

                              int maximumPoolSize,

                              long keepAliveTime,

                              TimeUnit unit,

                              BlockingQueue<Runnable> workQueue) {

        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

             Executors. defaultThreadFactory(), defaultHandler);

     }

service.schedule(callable,delay,unit);//线程,延迟,时间单位   每隔2s提交一次请求

 

public class ReadWriteLock {

      public static <E> void main(String[] args) {

            

            ExecutorService service = Executors. newCachedThreadPool();

            

             final ReadWrite readWrite = new ReadWrite();

            

             try {

                  Thread thread1 = new Thread( new Runnable() {

                         @Override

                         public void run() {

                               readWrite.writeLock( “this is write”);

                              

                        }

                  }, “AA”);

                   service.execute( thread1);     

                  

                   for( int i=1; i<=100; i++){

                        Thread thread2 = new Thread( new Runnable() {

                               @Override

                               public void run() {

                                     readWrite.readLock();

                              }

                        }, String. valueOf(i));

                         service.execute( thread2);

                  }

            } catch (Exception e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

            } finally{

                   service.shutdown();

            }

      }

}

 

 

8、常用工具类

CountDownLatch—-所有线程执行完才执行的任务(秦灭六国,一统华夏)

final CountDownLatch countDownLatch = new CountDownLatch(6);

countDownLatch .countDown();//没执行一条就-1,直到6条都执行完

countDownLatch .await();//阻塞最后一个要执行的主线程

 

public class CountDownLatchDemo {

      

      public static void main(String[] args) throws InterruptedException {

             //CountDownLatch

             final CountDownLatch countDownLatch = new CountDownLatch(6);

            

             for( int i=1; i<=6; i++){

                   new Thread( new Runnable() {

                        

                         @Override

                         public void run() {

                              System. out.println(Thread. currentThread().getName()+”\t 国家被灭”);

                               countDownLatch.countDown();

                        }

                  }, CountryEnums.forEachCountryEnums(i).getMsg()).start();

            }

            

             countDownLatch.await();

            System. out.println(Thread. currentThread().getName()+”\t 秦灭六国,一统华夏” );

      }

}

 

 

CyclicBarrier—集齐7颗龙珠,可以召唤神龙(其他线程执行完了只能等待)

 

public class CyclicBarrierDemo {

      

      private final static int number=7;

      

      public static void main(String[] args) {

             final CyclicBarrier cyclicBarrier = new CyclicBarrier(number, new Runnable() {

                   @Override

                   public void run() {

                        System. out.println( “集齐7颗龙珠,可以召唤神龙” );

                  }

            });

             for( int i=1; i<=7; i++){

                   final int temp= i;

                   new Thread( new Runnable() {

                         @Override

                         public void run() {

                               try {

                                    System. out.println(Thread. currentThread().getName()+”\t 收集第”+ temp+ “颗龙珠”);

                                     cyclicBarrier.await();

                              } catch (InterruptedException | BrokenBarrierException e) {

                                     e.printStackTrace();

                              }

                        }

                  }, String. valueOf(i)).start();

            }

            

      }

}

 

Semaphore—-信号灯(争车位)

 

public class SemaphoreDemo {

      public static void main(String[] args) {

             final Semaphore semaphore = new Semaphore(3); //模拟3个停车位

             for( int i=1; i<=6; i++){ //模拟6个汽车

                   new Thread( new Runnable() {

                        

                         @Override

                         public void run() {

                               try {

                                     semaphore.acquire();

                                    System. out.println(Thread. currentThread().getName()+ “\t 抢占到停车位” );

                                    TimeUnit. SECONDS.sleep( new Random().nextInt(5));

                                    System. out.println(Thread. currentThread().getName()+ “\t—- 离开了停车位” );

                              } catch (InterruptedException e) {

                                     e.printStackTrace();

                              } finally{

                                     semaphore.release();

                              }

                              

                        }

                  }, String. valueOf(i)).start();

            }

      }

}

 

9、集合不安全类

ArrayList、HashMap、HashSet

java.util.ConcurrentModificationException

CopyOnWriteArrayList();//写时复制

往元素中添加元素时,先复制一份新的数组(Arrays.copyOf),长度+1,把要添加的元素添加到新的数组中。最后把引用指向新的数组。(整个过程添加了reentrainLock)

CopyOnWriteArraySet<String>();

ConcurrentHashMap<>();

sss—->Arrays  Collections

三者对比:

 

1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

 

 

10、volatile

内存可见性 

 

public class SafeSingletonDemo {

      private static volatile SafeSingletonDemo safeSingletonDemo = null;

      private SafeSingletonDemo(){

            System. out.println( “********”+Thread. currentThread().getName());

      }

      

      //double check lock

      public static SafeSingletonDemo getInstance(){

             if( null == safeSingletonDemo){

                   synchronized (SafeSingletonDemo. class) {

                         if( null == safeSingletonDemo){

                               safeSingletonDemo= new SafeSingletonDemo();

                        }

                  }

            }

             return safeSingletonDemo;

      }

      

      public static void main(String[] args) {

             new Thread( new Runnable() {

                  

                   @Override

                   public void run() {

                        SafeSingletonDemo. getInstance();

                  }

            }, “AA”).start();

             new Thread( new Runnable() {

                  

                   @Override

                   public void run() {

                        SafeSingletonDemo. getInstance();

                  }

            }, “BB”).start();

             new Thread( new Runnable() {

                  

                   @Override

                   public void run() {

                        SafeSingletonDemo. getInstance();

                  }

            }, “CC”).start();

      }

}

彩蛋:某次公开课中记录的笔记

击穿缓存的方法:

口诀:读多写少用缓存,写多读少用队列,限流、分流

方法1:化并发为同步   

lock:等待锁:粗粒度的锁

1个线程拿到锁,重建缓存,

其他1999个线程等待,从redis取

方法2:互斥锁ConcurrentHashMap<> map     细粒度的锁

车次号1–>是否有锁

车次号2–>是否有锁

boolean lock = false;

lock = map.putIfAbsent(key,value)==null;//代表当前没有数据,不为null,当前有数据

if(lock){//拿到锁

     //重建缓存

     //再查一次

}else{//没拿到锁

     //缓存降级

     1:提示:当前人数太多,请耐心等待

}

 

    原文作者:JUC
    原文地址: https://blog.csdn.net/manongxiaomei/article/details/83927258
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞