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. 指令汇B新闻客户端开发(一) 新手引导页开发

    首先做开发的时候应该有一个闪屏页面和新手引导页, 我相信闪屏页面大家应该都会了,那么先看到新手引导页了. 我们可以看到这其实是一个ViewPager,我们也可以看到这是3个引导页,那么首先来看一下布局 ...

  2. Android Multimedia框架总结(一)MediaPlayer介绍之状态图及生命周期

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52349221 前言:从本篇开始,将进入Multimedia框架,包含 ...

  3. The Chain Of Responsibility (1)

    今天分享一下,设计模式中的责任链模式,其余的不过多叙述. 思路 在正式接触责任连之前,我们可以想象到的应该是一个链,链表?要处理一件事需要一个链似得?其实答案差不多就是这样.设计模式也都是从朴素的思维 ...

  4. linux ubuntu系统下MySQL的安装及设置

    debian下安装MySQL:1.构建源或使用光盘镜像,当然你插入光盘也没问题2.有源时本地文件的源配置:修改/etc/apt/sources.list文件, 示例:deb http://192.16 ...

  5. Bootstrap简单HelloWorld入门教程

    这篇教程旨在让你在20分钟内学会使用twitter bootstrap创建一个站点.看完这个教程后你应该能够使用bootstrap来建立一个基本的响应式布局的页面,了解栅格系统,并且能够使用boots ...

  6. 后端分布式系列:分布式存储-HDFS 与 GFS 的设计差异

    「后端分布式系列」前面关于 HDFS 的一些文章介绍了它的整体架构和一些关键部件的设计实现要点. 我们知道 HDFS 最早是根据 GFS(Google File System)的论文概念模型来设计实现 ...

  7. Linux下使用两个线程协作完成一个任务的简易实现

    刚解决了之前的那个Linux下Pthread库的问题,这次就来使用两个线程来协作,共同完成一个求和的任务. 打一下基础吧 本次需要使用到的知识点有: lpthread,编译的时候用到,相当于一个声明的 ...

  8. 1057. Stack (30) - 树状数组

    题目如下: Stack is one of the most fundamental data structures, which is based on the principle of Last ...

  9. React Native移植原生Android

    (一)前言 之前已经写过了有关React Native移植原生Android项目的文章,不过因为RN版本更新的原因吧,跟着以前的文章可能会出现一些问题,对于初学者来讲还是会有很多疑难的困惑的,而且官方 ...

  10. 15-5-23 下午02时22分58秒 CST> <Info> <Management> <BEA-141281> <unable to get file lock, will retry ...>

     A-141281> <unable to get file lock, will retry ...>   http://gdutlzh.blog.163.com/blog/s ...