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. 使用java命令重启tomcat

    public static void restartMyTomcat() { String location=ConfigUtil.getRestartLocation(); createCmdFil ...

  2. 1.关于QT中json数据处理和密码md5加密

     新建一个Qt空项目 17Json.pro HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += widgets gui MyWidget ...

  3. FFmpeg源代码简单分析:avformat_write_header()

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  4. 18 Ui美化

    资源文件的使用: 一: res中文件中放置的文件类型: res/drawable//放处理过的图片 res/drawable-XXX //放的Ui切得图 >res/anim 放动画 >re ...

  5. TCP的发送系列 — 发送缓存的管理(一)

    主要内容:TCP发送缓存的初始化.动态调整.申请和释放. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 数据结构 TCP对发送缓存的管理是在两个层面上进 ...

  6. Android进阶(二)https请求No peer certificate的解决方法.

    在做Android客户端通过https协议访问12306,并爬取数据时,出现了如下错误: 其中有一条错误提示是 javax.net.ssl.SSLPeerUnverifiedException: No ...

  7. java设计模式---职责链模式

    职责链的本质:分离职责,动态组合 样例: /** * 定义职责对象的接口 * */ public abstract class Handler { protected Handler successo ...

  8. 分布式内存网格Hazelcast源码导读

    去年项目需要看了hazelcast源码,当时记录的笔记. Node是节点的抽象,里面包含节点引擎.客户端引擎.分区服务.集群服务.组播服务.连接管理.命令管理.组播属性.节点配置.本地成员.tcp地址 ...

  9. Linux多线程实践(4) --线程特定数据

    线程特定数据 int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); int pthread_key_ ...

  10. java Serializable 生成随机序列

    如果你implements 了 Serializable接口 但是没写 UID,eclipse会在你的类名边上有一个警告,你点击一下,有一个选项自动生成 UID,所以请用eclipse写java代码