zoukankan      html  css  js  c++  java
  • 线程高级应用-心得3-线程范围内的共享变量以及应用场景及面试题案例分析

    1.知识点普及

    2.案例说明:线程范围内的共享变量以及应用场景(转账,转入和转出);在线程内共享,在线程外独立

      1 package com.itcast.family;
      2 
      3 import java.util.HashMap;
      4 import java.util.Map;
      5 import java.util.Random;
      6 
      7 /**
      8  * 案例说明:线程范围内的共享变量以及应用场景(转账,转入和转出);在线程内共享,在线程外独立
      9  */
     10 public class ThreadScopeShareData {
     11 
     12     //使不同模块拿到相同线程的相同数据
     13     private static Map<Thread,Integer> threadData = new HashMap<Thread, Integer>();
     14     public static void main(String[] args) {
     15         for (int i = 0; i < 2; i++) {
     16             new Thread(new Runnable() {
     17 
     18                 @Override
     19                 public void run() {
     20                     int data = new Random().nextInt();
     21                     System.out.println(Thread.currentThread().getName()
     22                             + " has put data: " + data);
     23                     threadData.put(Thread.currentThread(), data);
     24                     new A().get();
     25                     new B().get();
     26                 }
     27             }).start();
     28         }
     29     }
     30 
     31     static class A {
     32         public void get() {
     33             int data = threadData.get(Thread.currentThread());
     34             System.out.println("A from " + Thread.currentThread().getName()
     35                     + " get data: " + data);
     36         }
     37     }
     38 
     39     static class B {
     40         public void get() {
     41             int data = threadData.get(Thread.currentThread());
     42             System.out.println("B from " + Thread.currentThread().getName()
     43                     + " get data: " + data);
     44         }
     45     }
     46 }
     47 3. 使用ThreadLocal达到与上个案例相同的需求
     48 package com.itcast.family;
     49 
     50 import java.util.Random;
     51 
     52 /**
     53  * 使用ThreadLocal达到与上个案例相同的需求
     54  */
     55 public class ThreadLocalTest {
     56 
     57 
     58     //使不同模块拿到相同线程的相同数据
     59     //直接使用ThreadLocal传入数据
     60     private static ThreadLocal<Integer> threadData = new ThreadLocal<Integer>();
     61     //使用ThreadLocal传入对象中封装的数据;普通思路用到的变量
     62     //private static ThreadLocal<MyThreadScopeData> myData = new ThreadLocal<MyThreadScopeData>();
     63     public static void main(String[] args) {
     64         for (int i = 0; i < 2; i++) {
     65             new Thread(new Runnable() {
     66 
     67                 @Override
     68                 public void run() {
     69                     int data = new Random().nextInt();
     70                     System.out.println(Thread.currentThread().getName()
     71                             + " has put data: " + data);
     72                     threadData.set(data);
     73                     
     74                     //一般思路,符合基本的面向对象编程,但是用着啰嗦臃肿,代码不够优化    
     75 /*                    MyThreadScopeData myThread = new MyThreadScopeData();
     76                     myThread.setName("get nameData: "+data);
     77                     myThread.setAge(data);
     78                     myData.set(myThread);*/
     79                     
     80                     
     81                     //优雅和优化的思路,类似单例模式封装代码,因为使用者只需知道怎么用干什么用的,而不需知道内部代码是什么
     82                     MyThreadScopeData.getThreadInstance().setName(" get nameData: "+data);
     83                     MyThreadScopeData.getThreadInstance().setAge(data);
     84                     new A().get();
     85                     new B().get();
     86                 }
     87             }).start();
     88         }
     89     }
     90 
     91     static class A {
     92         public void get() {
     93             int data = threadData.get();
     94             System.out.println("A from " + Thread.currentThread().getName()
     95                     + " get data: " + data);
     96     
     97             //一般思路,符合基本的面向对象编程,但是用着啰嗦臃肿,代码不够优化
     98 /*            MyThreadScopeData myThread = myData.get();
     99             System.out.println("A from " + Thread.currentThread().getName()
    100                      + myThread.getName()+" ;get ageData: "+myThread.getAge());*/
    101             
    102             
    103             //优雅和优化的思路,类似单例模式封装代码,因为使用者只需知道怎么用干什么用的,而不需知道内部代码是什么
    104             MyThreadScopeData myThread = MyThreadScopeData.getThreadInstance();
    105             System.out.println("A from " + Thread.currentThread().getName()
    106                      + myThread.getName()+" ; get ageData: "+myThread.getAge());
    107         }
    108     }
    109 
    110     static class B {
    111         public void get() {
    112             int data = threadData.get();
    113             System.out.println("B from " + Thread.currentThread().getName()
    114                     + " get data: " + data);
    115             
    116 /*            MyThreadScopeData myThread = myData.get();
    117             System.out.println("B from " + Thread.currentThread().getName()
    118                      + myThread.getName()+" ;get ageData: "+myThread.getAge());*/
    119             
    120             MyThreadScopeData myThread = MyThreadScopeData.getThreadInstance();
    121             System.out.println("B from " + Thread.currentThread().getName()
    122                      + myThread.getName()+" ; get ageData: "+myThread.getAge());
    123         }
    124     }
    125 }
    126 
    127 class MyThreadScopeData{
    128     //可以参考单例模式来编写更加优化和优雅的线程代码
    129     private MyThreadScopeData(){}
    130      //线程这里与单例有些许不同,因为只有一个对象,所以可以不用使用同步锁
    131     public static/*synchronized*/MyThreadScopeData getThreadInstance(){
    132         MyThreadScopeData instance = map.get();
    133         if(instance == null){
    134             instance = new MyThreadScopeData();
    135             map.set(instance);
    136         }
    137         return instance;
    138     }
    139     
    140     /*只是告诉阅读者类似单例代码,但是与单例不同
    141      * private static MyThreadScopeData intance = null;//new MyThreadScopeData(); 
    142     //饱汉式,不管用不用先new出来;这里用饿汉式,用的时候才new出来
    143     */    
    144     private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
    145     private String name;
    146     private int age;
    147     public String getName() {
    148         return name;
    149     }
    150     public void setName(String name) {
    151         this.name = name;
    152     }
    153     public int getAge() {
    154         return age;
    155     }
    156     public void setAge(int age) {
    157         this.age = age;
    158     }
    159     
    160 }
    161 4. 面试题: 设计4个成员,其中两个线程每次对j加1;另两个线程每次对j减1,代码如下分析:
    162 
    163 package com.itcast.family;
    164 
    165 /**
    166  * 面试题:
    167  *    设计4个成员,其中两个线程每次对j加1;
    168  * 另两个线程每次对j减1,代码如下分析:
    169  */
    170 public class MultiThreadShareData {
    171     
    172     // 面试题答案:
    173     private int j;
    174 
    175     public static void main(String[] args) {
    176         MultiThreadShareData data = new MultiThreadShareData();
    177         Inc inc = data.new Inc();
    178         Dec dec = data.new Dec();
    179         //创建四个线程,如题:两个增加两个减少
    180         for (int i = 0; i < 2; i++) {
    181             new Thread(inc).start();
    182             new Thread(dec).start();
    183         }
    184     }
    185 
    186     /*
    187      * 不直接把j++或j--写到对应的实现Runnable类的代码中,
    188      * 而是抽出成外部类的两个方法;是因为外部类的方法方便使用
    189      * 同步锁,更容易控制并发问题
    190      */
    191     private synchronized void inc() {
    192         j++;
    193         System.out.println(Thread.currentThread().getName() + "-inc:" + j);
    194     }
    195 
    196     private synchronized void dec() {
    197         j--;
    198         System.out.println(Thread.currentThread().getName() + "-dec:" + j);
    199     }
    200 
    201     class Inc implements Runnable {
    202 
    203         @Override
    204         public void run() {
    205             for (int i = 0; i < 100; i++) {
    206                 inc();
    207             }
    208         }
    209 
    210     }
    211 
    212     class Dec implements Runnable {
    213 
    214         @Override
    215         public void run() {
    216             for (int i = 0; i < 100; i++) {
    217                 dec();
    218             }
    219         }
    220 
    221     }
    222     
    223     
    224 
    225     
    226     /*//第一种方案传入的data变量要么是静态成员变量要么是最终普通变量,否则会出错;因为两个内部类访问可以访问同一个外部类的成员变量
    227     private static ShareData data1 = new ShareData();
    228     public static void main(String[] args) {
    229         final ShareData data1 = new ShareData();
    230         ShareData data2 = new ShareData();
    231         
    232         //第一种方案:这两个线程分别实现两个Runnable的run方法,分别用来执行加减
    233         new Thread(new Runnable() {
    234             
    235             @Override
    236             public void run() {
    237                 data1.increment();
    238             }
    239         }).start();
    240         new Thread(new Runnable() {
    241             
    242             @Override
    243             public void run() {
    244                 data1.decrement();
    245             }
    246         }).start();
    247         
    248         //第二种方案:传入实现了Runnable接口的类对象,相应的需求方法封装在传入的类中
    249         new Thread(new MyRunnable1(data2)).start();
    250         new Thread(new MyRunnable2(data2)).start();
    251 
    252     }
    253 
    254 }
    255 
    256 //第二种方案
    257 class MyRunnable1 implements Runnable{
    258     private ShareData data;
    259     MyRunnable1(ShareData data) {
    260         super();
    261         this.data = data;
    262     }
    263 
    264     public void run() {
    265         data.increment();
    266     }
    267 }
    268 class MyRunnable2 implements Runnable{
    269     private ShareData data;
    270     MyRunnable2(ShareData data) {
    271         super();
    272         this.data = data;
    273     }
    274     
    275     public void run() {
    276         data.decrement();
    277     }
    278 }
    279 
    280 
    281 //因为需求是一个加一个减,即两个不同的线程,仅实现一个Runnable接口是不够的
    282 class ShareData{ implements Runnable{
    283     private int count = 100;
    284     @Override
    285     public void run() {
    286         while(true){
    287             count --;
    288         }
    289     }
    290    
    291     private int j = 0;
    292     public void increment(){
    293         j++;
    294     }
    295     public void decrement(){
    296         j--;
    297 
    298     }
    299     */
    300 }
  • 相关阅读:
    C++ ORM ODB 入门(三)
    C++ ORM ODB 入门介绍(二)
    最简便的MySql数据库备份方法
    快速高效的破解MySQL本地和远程密码
    C++ ORM ODB 入门介绍(一)
    NeHe OpenGL教程 第三十九课:物理模拟
    NeHe OpenGL教程 第三十八课:资源文件
    NeHe OpenGL教程 第三十七课:卡通映射
    NeHe OpenGL教程 第三十六课:从渲染到纹理
    NeHe OpenGL教程 第三十五课:播放AVI
  • 原文地址:https://www.cnblogs.com/cxxjohnson/p/6261889.html
Copyright © 2011-2022 走看看