• 并发concurrent---2


    背景:并发知识是一个程序员段位升级的体现,同样也是进入BAT的必经之路,有必要把并发知识重新梳理一遍。

    并发concurrent:

    使用ThreadLocal可以实现线程范围内共享变量,线程A写入的值和线程B获取到的结果一致;ReentrantReadWriteLock允许多个读线程或多个写线程同时进行,但不允许写线程和读线程同时进行;使用Callable可以得到线程执行的返回结果;Exchanger可以相互交换家线程执行的结果;这些使用方法大致都一样,JDk参考文档里面哪里不会点哪里,下面写个ThreadLocal实现线程范围内变量共享,里面还用到了一下饿汉模式:

    执行结果如图中控制台打印,使用ThreadLocal保证了线程0和线程1读取到的值与写入的一致。

     1 import java.util.Random;
     2 import java.util.concurrent.locks.ReentrantReadWriteLock;
     3 import lombok.Data;
     4 
     5 public class ThreadLocalTest {
     6     //ThreadLocal 实现线程范围内共享变量
     7     private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
     8     private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
     9     public static void main(String[] args) {
    10         new ReentrantReadWriteLock();
    11         for(int i = 0; i<2; i++) {
    12             new Thread(new Runnable() {
    13                 @Override
    14                 public void run() {
    15                     int data = new Random().nextInt();
    16                     System.out.println(Thread.currentThread().getName()
    17                             +" has put data: "+ data);
    18                     x.set(data);  // 存的时候与当前线程相关 取的时候也是与当前线程相关
    19                     //MyThreadScopeData.getInstance()拿到与本线程实例相关的对象: 不用反复new对象来getter/setter
    20                     MyThreadScopeData.getThreadInstance().setName("name: "+data);
    21                     MyThreadScopeData.getThreadInstance().setAge(data);
    22                     new A().get();
    23                     new B().get();
    24                 }
    25             }).start();
    26         }
    27 }
    28     
    29     static class A{
    30         public void get() {
    31             int data = x.get();
    32             System.out.println("A from "+Thread.currentThread().getName()+" get data: "+data);
    33             //MyThreadScopeData.getInstance()拿到与本线程实例相关的对象
    34             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
    35             System.out.println("A from "+Thread.currentThread().getName()
    36                     +" getMyData: "+myData.getName() +","+myData.getAge());
    37         }
    38     }
    39     
    40     static class B{
    41         public void get() {
    42             int data = x.get();
    43             System.out.println("B from "+Thread.currentThread().getName()+" get data: "+data);
    44             //MyThreadScopeData.getInstance()拿到与本线程实例相关的对象
    45             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
    46             System.out.println("B from "+Thread.currentThread().getName()
    47                     +" getMyData: "+myData.getName() +","+myData.getAge());
    48         }
    49     }
    50     
    51     //设计自己线程范围内变量的共享,不需要创建对象,只需调用线程即可用到线程内的变量
    52     @Data
    53     static class MyThreadScopeData{
    54         //构造方法私有化,外部没发直接调用,但是可以调用里面的静态方法
    55         private MyThreadScopeData() { }
    56         public static /*synchronized*/ MyThreadScopeData getThreadInstance() {
    57             MyThreadScopeData instance = map.get();
    58             if (instance == null) {
    59                 //饿汉模式 : 第一次来创建
    60                 instance = new MyThreadScopeData();
    61                 map.set(instance);
    62             }
    63             return instance;
    64         }
    65     //    private static MyThreadScopeData instance = null; // new MyThreadScopeData();
    66         private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
    67         private String name;
    68         private int age;
    69     }
    70 
    71 }

    网上还有一个多线程面试很有趣的题目:子线程执行10次,主线程执行100次,接着子线程再执行10次,主线程继续再执行100次,往复循环50次;

     1 //Java多线程面试: 子线程执行10次,主线程执行100次,接着子线程再10次,主线程再执行100次,往复循环50次
     2 public class ThreadCommunication {
     3     public static void main(String[] args) {
     4      Business business = new Business();
     5     new Thread(
     6             new Runnable() {
     7         @Override
     8         public void run() {
     9             for (int i = 1; i <= 50; i++) {
    10                 business.sub(i);
    11             }
    12         }
    13     }).start();
    14     
    15     for (int i = 1; i <= 50; i++) {
    16         business.main(i);
    17     }
    18     }
    19     
    20     //把主线程和自线程执行的方法归结到一个类(共同算法的若干方法),巧妙设计,好维护高聚合,健壮性;
    21     public static class Business{
    22         //子线程方法
    23         private boolean bShouldSub = true;
    24         public synchronized void sub(int i) {
    25             while(!bShouldSub) {
    26                 //用while比if更好,可以防止线程被伪唤醒
    27                 try {
    28                     this.wait(); // 如果不是子线程方法该执行的,则令其等待
    29                 } catch (InterruptedException e) {
    30                     e.printStackTrace();
    31                 }
    32             }
    33             for(int j = 1; j<= 10; j++) {
    34                 System.out.println("sub thread sequence of "+j + ",loop of "+ i);
    35             }
    36             bShouldSub = false;
    37             this.notify(); //唤醒主线程方法
    38         }        
    39     
    40     //主线程方法
    41     public synchronized void main(int i) {
    42         while(!bShouldSub) {
    43             try {
    44                 this.wait();  // 如果不是主线程方法该执行的,则令其等待
    45             } catch (InterruptedException e) {
    46                 e.printStackTrace();
    47             }
    48         }
    49         for(int j = 1; j<= 100; j++) {
    50             System.out.println("main thread sequence of "+j + ",loop of "+ i);
    51         }
    52         bShouldSub = true;
    53         this.notify();  // 唤醒子线程方法
    54     }
    55     }
    56 }

    线程池:

    1、固定线程数目的线程池newFixedThreadPool;

    2、缓存线程数目的线程池newCachedThreadPool;

    3、单一线程池newSingleThreadExecutor;

    4、定时器线程池newScheduledThreadPool;

     1 package com.xinyan.springcloud.controller;
     2 
     3 import java.util.concurrent.ExecutorService;
     4 import java.util.concurrent.Executors;
     5 import java.util.concurrent.TimeUnit;
     6 
     7 public class ThreadPoolTest {
     8     public static void main(String[] args) {
     9         //固定线程数目的线程池  3个
    10          ExecutorService threadPool = Executors.newFixedThreadPool(3);
    11         //缓存线程数目的线程池即动态变化  当任务过来了,线程池内部会自动增加线程,空闲后线程又被回收,线程数目不定
    12         //ExecutorService threadPool = Executors.newCachedThreadPool();
    13         //单一线程池
    14         //ExecutorService threadPool = Executors.newSingleThreadExecutor(); 
    15         //往线程池中放入10个任务:
    16         for(int i = 1; i<= 10; i++) {
    17             final int task = i; // task被final修饰不能变了,但是i 可以变
    18             threadPool.execute(new Runnable() {
    19                 @Override
    20                 public void run() {
    21                     for(int j =1; j<=10; j++) {
    22                         try {
    23                             Thread.sleep(200);
    24                         } catch (InterruptedException e) {
    25                             e.printStackTrace();
    26                         }
    27                         //System.out.println(Thread.currentThread().getName()+" loop of "+ j +" task is "+ task);
    28                     }
    29                 }
    30             });
    31         }
    32         System.out.println("所有的10个任务已经全部提交。");   //任务都提交了,交由线程池去搞
    33         threadPool.shutdown();   //没有任务后关闭线程
    34           //threadPool.shutdownNow();    //还有任务没有给执行完毕就立即关闭线程
    35         
    36         //定时器线程池: 3个线程  
    37         System.out.println("敌军还有5秒到达战场.");
    38         Executors.newScheduledThreadPool(3).schedule(new Runnable() {
    39             @Override
    40             public void run() {
    41                 System.out.println("敌军抵达战场,碾碎她们。");
    42             }
    43             //5秒后执行线程池内run方法
    44         }, 5, TimeUnit.SECONDS);
    45         //Executors.newScheduledThreadPool(3)scheduleAtFixedRate(command, initialDelay, period, unit)
    46         //scheduleAtFixedRate 定时循环执行线程池内方法
    47     }
    48 }
  • 相关阅读:
    Intern Day15
    Intern Day15
    Intern Day15
    Intern Day15
    Intern Day15
    Intern Day14
    Intern Day14
    纯CSS序列号
    屌丝、高富帅、文艺青年、土豪的区别
    什么是文艺
  • 原文地址:https://www.cnblogs.com/taojietaoge/p/10293651.html
Copyright © 2020-2023  润新知