• JAVA多线程学习八-多个线程之间共享数据的方式


    多个线程访问共享对象和数据的方式

    如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做。 

    如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享: 

    Ø将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

    Ø将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。 

    Ø上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。

    Ø总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。

    极端且简单的方式,即在任意一个类中定义一个static的变量,这将被所有线程共享。

    需求:设计4个线程,其中两个线程每次对j增加1,另外两个线程对j减少1.

    1.使用同一个runnable对象

    如果每个线程执行的代码相同,那么可以使用同一个runnable对象,这个runnable有那个共享数据,例如,卖票系统就是这么做的.

    复制代码
    ...
        public static void main(String[] args) {
            ShareData1 shareData1 = new ShareData1();
            new Thread(shareData1).start();
            new Thread(shareData1).start();
        }
    
        static class ShareData1 implements Runnable {
            public int count = 100;
            public void run() {
                count--;
                System.out.println("run:"+count);
            }
        }
    
    ...
    复制代码

    2.使用不同的runnable对象

    如果每个线程执行的代码不同,那么要使用不同的runnable对象,有如下两种方式可以实现runnable对象间的数据共享

    1).实现两个runnable对象,将共享数据分别传递给两个不同线程.

    复制代码
    ....
    public static void main(String[] args) {
            final ShareData1 shareData1 = new ShareData1();
            new Thread(new MyRunnable1(shareData1)).start();
            new Thread(new MyRunnable1(shareData1)).start();
    }
    static class MyRunnable1 implements Runnable{
            private ShareData1 shareData1;
            public void run() {
            }
            public MyRunnable1(ShareData1 shareData1){
                this.shareData1 = shareData1;
            }
        }
    static class MyRunnable2 implements Runnable{
            private ShareData1 shareData1;
            public void run() {
            }
            public MyRunnable2(ShareData1 shareData1){
                this.shareData1 = shareData1;
            }
        }
    static class ShareData1 {
    ....
    }
    ......
    复制代码

    2).将这些Runnable对象作为一个内部类,将共享数据作为成员变量.

    复制代码
    public class MultiThreadShareData {
        private int j;
        public static void main(String[] args) {
            MultiThreadShareData multiThreadShareData = new MultiThreadShareData();
            for(int i=0;i<2;i++){
                new Thread(multiThreadShareData.new ShareData1()).start();//增加
                new Thread(multiThreadShareData.new ShareData2()).start();//减少
            }
        }
        //自增
        private synchronized void Inc(){
            j++;
            System.out.println(Thread.currentThread().getName()+" inc "+j);
        }
        //自减
        private synchronized void Dec(){
            j--;
            System.out.println(Thread.currentThread().getName()+" dec "+j);
        }
        
        class ShareData1 implements Runnable {
            public void run() {
                for(int i=0;i<5;i++){
                    Inc();
                }
            }
        }
        class ShareData2 implements Runnable {
            public void run() {
                for(int i=0;i<5;i++){
                    Dec();
                }
            }
        }
    }
    复制代码

    效果:

    注:

    1.上面的代码,首先,是定义了一个全局的变量j,即共享数据;然后,实现Runnable对象,分别去做自增和自减的操作,然后将实现了的Runnable对象作为一个内部类塞给新建的线程;最后循环两遍,实现两个自减和两个自增线程.

    2.这里要注意的是之所以将自增和自减提出来,是为了方便进行线程安全控制.

    3.方法二和方法一的区别在于,方法一是主动将共享数据赋给Runnable对象,方法二则是将数据置为全局变量,然后进行操作.

  • 相关阅读:
    JavaScript中的闭包
    SQL 备忘
    SqlServer 2005 升级至SP2过程中出现"身份验证"无法通过的问题
    unable to start debugging on the web server iis does not list an application that matches the launched url
    Freebsd 编译内核
    Freebsd 6.2中关于无线网络的设定
    【Oracle】ORA01219
    【Linux】Windows到Linux的文件复制
    【Web】jar命令行生成jar包
    【Linux】CIFS挂载Windows共享
  • 原文地址:https://www.cnblogs.com/guanbin-529/p/13363689.html
Copyright © 2020-2023  润新知