java基础巩固笔记5-多线程之共享数据

线程范围内共享数据

ThreadLocal类

多线程访问共享数据

几种方式

本文主要总结线程共享数据的相关知识,主要包括两方面:一是某个线程内如何共享数据,保证各个线程的数据不交叉;一是多个线程间如何共享数据,保证数据的一致性。





线程范围内共享数据





自己实现的话,是定义一个Map,线程为键,数据为值,表中的每一项即是为每个线程准备的数据,这样在一个线程中数据是一致的。





例子





package com.iot.thread;





import java.util.HashMap;

import java.util.Map;

import java.util.Random;





/**

 * Created by brian on 2016/2/4.

 */

public class ThreadScopeShareData {

    //准备一个哈希表,为每个线程准备数据

    private  static Map<Thread,Integer> threadData = new HashMap<>();

    public static void main(String[] args) {

        for(int i=0;i<2;i++){

            new Thread(

                    new Runnable() {

                @Override

                public void run() {

                    int data = new Random().nextInt();

                    threadData.put(Thread.currentThread(),data);

                    System.out.println(Thread.currentThread()+" put data:"+data);

                    new A().get();

                    new B().get();

                }

            }).start();

        }

    }

   static  class A{

        public void get(){

            int data = threadData.get(Thread.currentThread());

            System.out.println("A from "+Thread.currentThread()+" get data "+data);

        }

    }





    static  class B{

        public void get(){

            int data = threadData.get(Thread.currentThread());

            System.out.println("B from "+Thread.currentThread()+" get data "+data);

        }

    }

}





上述代码偶尔会报异常:





Exception in thread "Thread-0" java.lang.NullPointerException

    at com.iot.thread.ThreadScopeShareData$A.get(ThreadScopeShareData.java:29)

    at com.iot.thread.ThreadScopeShareData$1.run(ThreadScopeShareData.java:21)

    at java.lang.Thread.run(Thread.java:745)

1

2

3

4

5

具体原因还不知道





ThreadLocal类





API:





java.lang:Class ThreadLocal<T>

单变量

使用ThreadLocal类型的对象代替上面的Map即可





多变量

定义一个对象来封装多个变量,然后在ThreadLocal中存储整个对象





多变量时,最好将ThreadLocal类放在数据类的内部,数据类采用单例模式,这样,新建对象和获取对象都会更方便,同时封装性更强。





示例代码:





package com.iot.thread;





import java.util.Random;





/**

 * Created by brian on 2016/2/4.

 */

public class ThreadLocalTest {

    private  static ThreadLocal<Integer> threadInger = new ThreadLocal<>();

    public static void main(String[] args) {

        for(int i=0;i<2;i++){

            new Thread(new Runnable() {

                @Override

                public void run() {

                    int data = new Random().nextInt(100);

                    threadInger.set(data);

                    System.out.println(Thread.currentThread()+" put data:"+data);

                    MyThreadScopeData.getThreadInstance().setName(Thread.currentThread().toString());

                    MyThreadScopeData.getThreadInstance().setAge(data%10);

                    new A().get();

                    new B().get();

                }

            }).start();

        }

    }

    static  class A{

        public void get(){

            int data = threadInger.get();

            System.out.println("A from "+Thread.currentThread()+" get data "+data);

            MyThreadScopeData myThreadScopeData = MyThreadScopeData.getThreadInstance();

            System.out.println("A from "+myThreadScopeData);





        }

    }





    static  class B{

        public void get(){

            int data = threadInger.get();

            System.out.println("B from "+Thread.currentThread()+" get data "+data);

            MyThreadScopeData myThreadScopeData = MyThreadScopeData.getThreadInstance();

            System.out.println("B from "+myThreadScopeData);

        }

    }

}





/**

 * 将多变量封装起来的数据类

 * 单例模式,内置ThreadLocal类型变量

 */

class MyThreadScopeData{





    private MyThreadScopeData(){}





    private static ThreadLocal<MyThreadScopeData> data = new ThreadLocal<>();





    public static  MyThreadScopeData getThreadInstance(){

        MyThreadScopeData instance = data.get();

        if(instance == null){

            instance = new MyThreadScopeData();

            data.set(instance);

        }

        return instance;

    }













    private String name;

    private int age;

    public String getName() {

        return name;

    }





    public void setName(String name) {

        this.name = name;

    }





    public int getAge() {

        return age;

    }





    public void setAge(int age) {

        this.age = age;

    }





    @Override

    public String toString() {

        String reVal = super.toString()+"-{name,age}"+":{"+getName()+","+getAge()+"}";

        return reVal;

    }

}









多线程访问共享数据





几种方式





线程执行代码相同,使用同一Runnable对象,Runnable对象中有共享数据

线程执行代码不同,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),将这个对象逐一传递给各个Runnable对象。[本质:共享数据的对象作为参数传入Runnable对象]

线程执行代码不同,将Runnable对象作为某一个类的内部类,共享数据作为这个外部类的成员变量(操作数据的方法放在外部类)。[本质:不同内部类共享外部类数据]

结合上两种方式,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),该对象作为这个外部类的成员变量,将Runnable对象作为内部类

最后一种方式的示例:





设计5个线程,其中三个线程每次对j增加1,另外两个线程对j每次减少1





package com.iot.thread;





/**

 * Created by brian on 2016/2/4.

 */

public class MutiThreadShareData {





    private static MutiShareData mutiShareData = new MutiShareData();





    public static void main(String[] args) {





        for(int i=0;i<3;i++){

            new Thread(

                    new Runnable() {

                        @Override

                        public void run() {

                            System.out.println(Thread.currentThread()+":{j from "+ mutiShareData.getJ()+" + to: "+mutiShareData.increment()+"}");

                        }

                    }

            ).start();

        }





        for(int i=0;i<2;i++){

            new Thread(

                    new Runnable() {

                        @Override

                        public void run() {

                            System.out.println(Thread.currentThread()+":{j from "+ mutiShareData.getJ()+" - to: "+mutiShareData.decrement()+"}");

                        }

                    }

            ).start();

        }

    }





}





/**

 * 将共享数据封装在另一对象中(操作数据的方法也在该对象完成)

 */

class MutiShareData{

    private int j = 0;

    public synchronized  int increment(){

        return  ++j;

    }

    public synchronized int  decrement(){

        return --j;

    }





    public synchronized int getJ() {

        return j;

    }





    public synchronized void setJ(int j) {

        this.j = j;

    }

}

java基础多线程之共享数据的更多相关文章

  1. Java基础-线程操作共享数据的安全问题

    Java基础-线程操作共享数据的安全问题 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.引发线程安全问题 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运 ...

  2. Java基础-多线程-③线程同步之synchronized

    使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...

  3. Java基础-多线程-②多线程安全问题

    什么是线程的安全问题? 上一篇 Java基础-多线程-①线程的创建和启动 我们说使用实现Runnable接口的方式来创建线程,可以实现多个线程共享资源: class Dog implements Ru ...

  4. 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!

    前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...

  5. java基础-多线程应用案例展示

    java基础-多线程应用案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.两只熊,100只蜜蜂,蜜蜂每次生产的蜂蜜量是1,罐子的容量是30,熊在罐子的蜂蜜量达到20的时候 ...

  6. java基础-多线程二

    java基础-多线程二 继承thread和实现Runnable的多线程每次都需要经历创建和销毁的过程,频繁的创建和销毁大大影响效率,线程池的诞生就可以很好的解决这一个问题,线程池可以充分的利用线程进行 ...

  7. 笔记||Pyhthon3进阶之多线程操作共享数据

    # 多线程操作共享数据--------------------------------------------------------------- # import threading# 使用锁# ...

  8. Java基础——多线程

    Java中多线程的应用是非常多的,我们在Java中又该如何去创建线程呢? http://www.jianshu.com/p/40d4c7aebd66 一.常用的有三种方法来创建多线程 新建一个类继承自 ...

  9. Java基础--多线程的方方面面

    1,什么是线程?线程和进程的区别是什么? 2,什么是多线程?为什么设计多线程? 3,Java种多线程的实现方式是什么?有什么区别? 4,线程的状态控制有哪些方法? 5,线程安全.死锁和生产者--消费者 ...

随机推荐

  1. 阻尼回弹效果的ScrollView嵌套GridView

    以前写过一篇带阻尼回弹效果的ScrollView,但是有些小问题,于是又重新整理了一下,这篇文章一是一个带阻尼的Scrollview,再个就是Scrollview嵌套GridView实现,而GridV ...

  2. 【一天一道LeetCode】#303.Range Sum Query - Immutable

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 我的个人博客已创建,欢迎大家持续关注! 一天一道le ...

  3. Mybatis源码分析之缓存

    一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...

  4. 安卓TextView完美展示html格式代码

    对于TextView展示html格式代码,最简单的办法就是使用textview.setText(Html.fromHtml(html));,即便其中有img标签,我们依然可以使用ImageGetter ...

  5. 2.3、Android Studio使用Layout Editor设计UI

    Android Studio提供了一个高级的布局编辑器,允许你拖拽控件,在编辑XML之后可以实时预览. 在布局编辑器中,你在文字视图和设计视图直接来回切换. 在文字视图中编辑 你可以在文字视图中编辑你 ...

  6. 详解EBS接口开发之供应商导入(补充)--供应商银行账户更新

    CREATE OR REPLACE PACKAGE BODY update_vendor_account IS PROCEDURE main(errbuf OUT VARCHAR2, retcode ...

  7. SSH网上商城---需求分析+表关系分析

    SSH---小编初次接触的时候傻傻的以为这个跟SHE有什么关系呢?又是哪路明星歌手,后来才知道小编又土鳖了,原来SSH是这个样子滴,百度百科对她这样阐述,SSH即 Spring + Struts +H ...

  8. Android开发学习之路--Activity之四种启动模式

    后天终于可以回家了,马上就要过年了,趁着年底打酱油的模式,就多学习学习,然后记录记录吧.关于Activity已经学习了七七八八了,还有就是Activity的四种启动模式了,它们分别为,standard ...

  9. Java进阶(三十二) HttpClient使用详解

    Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...

  10. visual studio 2015使用python tools远程调试maya 2016

    步骤: 1. 去https://apps.exchange.autodesk.com/MAYA/en/Home/Index搜索Developer Kit并下载,maya 2016可以直接点击这里下载. ...