zoukankan      html  css  js  c++  java
  • java多线程与线程并发四:线程范围内的共享数据

    当多个线程操作同一个共有数据时,一个线程对共有数据的改变会影响到另一个线程。比如下面这个例子:两个线程调用同一个对象的的方法,一个线程的执行结果会影响另一个线程。

     1 package com.sky.thread;
     2 
     3 public class TestThreadLocal {
     4     public static void main(String[] args) {
     5         final ThreadLocalBiz biz = new ThreadLocalBiz();
     6         new Thread(new Runnable() {
     7 
     8             @Override
     9             public void run() {
    10                 while (true) {
    11                     try {
    12                         Thread.sleep(500);
    13                     } catch (InterruptedException e) {
    14                         // TODO Auto-generated catch block
    15                         e.printStackTrace();
    16                     }
    17                     biz.add();
    18                     
    19                 }
    20             }
    21         }).start();
    22         new Thread(new Runnable() {
    23 
    24             @Override
    25             public void run() {
    26                 while (true) {
    27                     try {
    28                         Thread.sleep(500);
    29                     } catch (InterruptedException e) {
    30                         // TODO Auto-generated catch block
    31                         e.printStackTrace();
    32                     }
    33                     biz.add();
    34                     
    35                 }
    36             }
    37         }).start();
    38     }
    39 }
    40 
    41 class ThreadLocalBiz {
    42     private int num = 0;
    43 
    44     public synchronized void add() {
    45         num++;
    46         System.out.println("线程:" + Thread.currentThread().getName() + "num:"
    47                 + num);
    48     }
    49 }
    线程结果互相影响

    执行的结果是:

    线程:Thread-0num:1
    线程:Thread-1num:2
    线程:Thread-0num:3
    线程:Thread-1num:4
    执行结果

    可见,Thread-0执行完以后,num的值是1。当Thread-1开始执行时,num的值对它而言是1而不是一开始的0,所以在Thread-1执行完以后,num的值变成了2。

    如果我们想让两个线程在操作同一个共有数据时,互相的操作结果互不影响该怎么办?

    这个时候可以使用ThreadLocal。先看下面的代码:

     1 package com.sky.thread;
     2 
     3 public class TestThreadLocal {
     4     
     5     
     6     public static void main(String[] args) {
     7         new Thread(new Runnable() {
     8 
     9             @Override
    10             public void run() {
    11                 while (true) {
    12                     try {
    13                         Thread.sleep(500);
    14                     } catch (InterruptedException e) {
    15                         // TODO Auto-generated catch block
    16                         e.printStackTrace();
    17                     }
    18                     
    19                     ThreadLocalBiz.getBiz().add();
    20                     
    21                 }
    22             }
    23         }).start();
    24         new Thread(new Runnable() {
    25 
    26             @Override
    27             public void run() {
    28                 while (true) {
    29                     try {
    30                         Thread.sleep(1000);
    31                     } catch (InterruptedException e) {
    32                         // TODO Auto-generated catch block
    33                         e.printStackTrace();
    34                     }
    35                     
    36                     ThreadLocalBiz.getBiz().add();
    37                     
    38                 }
    39             }
    40         }).start();
    41     }
    42 }
    43 
    44 class ThreadLocalBiz {
    45     private int num = 0;
    46     public static ThreadLocal<ThreadLocalBiz> LocalBiz = new ThreadLocal<ThreadLocalBiz>();
    47     
    48     private ThreadLocalBiz(){}
    49     public static ThreadLocalBiz getBiz(){
    50         ThreadLocalBiz biz = LocalBiz.get();
    51         if (biz == null) {
    52             biz = new ThreadLocalBiz();
    53             LocalBiz.set(biz);
    54         }
    55         return biz;
    56     }
    57     public void add() {
    58         num++;
    59         System.out.println("线程:" + Thread.currentThread().getName() + ",num:"
    60                 + num);
    61     }
    62     
    63 }
    View Code
    线程:Thread-0,num:1
    线程:Thread-1,num:1
    线程:Thread-0,num:2
    线程:Thread-0,num:3
    线程:Thread-1,num:2
    执行结果

    这段代码的基本思路是,为不同的线程创建单独的实例。比如上面这段代码,有两个线程调用的ThreadLocalBiz的add方法,那么一共创建的两个ThreadLocalBiz实例。每个线程操作自己的专属实例,自然就不会相互干扰了。

    在这段代码中,getBiz和add方法都没有加synchronized,就是因为单个实例只对应单个线程,不存在并发问题,自然也就不用加互斥锁了。

    现在来仔细说说ThreadLocal。

    ThreadLocal相当于一个Map。以当前线程作为key。

    下面的代码

    ThreadLocal<ThreadLocalBiz> LocalBiz = new ThreadLocal<ThreadLocalBiz>();
    LocalBiz.set(new ThreadLocalBiz());
    LocalBiz.get();

    就相当于

    Map<Thread, ThreadLocalBiz> ThreadMap = new HashMap<Thread, ThreadLocalBiz>();
    ThreadMap.put(Thread.currentThread(), new ThreadLocalBiz());
    ThreadMap.get(Thread.currentThread());

    可见,ThreadLocal完全可以被Map代替。java只是代为封装了一下。

  • 相关阅读:
    <<SQL Server 2005 高级程序设计>> 学习笔记(4)
    ASP.NET发布网站的二个小问题总结
    Android AlertDialog 实例
    SQL2005 导入其它服务器数据
    Android sysout.exit(0) 和finish()区别
    <<SQL Server 2005 高级程序设计>> 学习笔记(3)
    ASP.NET上传多个文件
    <<SQL Server 2005 高级程序设计>> 学习笔记(1)
    SurfaceView 间取得焦点
    图像处理类
  • 原文地址:https://www.cnblogs.com/bailiyi/p/3650291.html
Copyright © 2011-2022 走看看