zoukankan      html  css  js  c++  java
  • 线程系列6--多个线程之间共享数据的方式

    多线程共享数据的方式:

    1,如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做。网上搜出来的东西都直接这样解说,包括传智播客中张孝祥也是这么讲的。但是我却迷茫了好久,为啥这个Runnable实现的多线程共享数据,在没有采取任何措施的情况下,没有出现执行混乱。当然网上没有找到我想要的答案。后来还是自己想明白了,虽然Runnable能实现数据对象共享,但是它并不能保证程序执行不混乱(自己代码测试)。大家可以试一下,可以在买票系统的方法中多加几行代码就会发现执行混乱问题。下面代码所示:

    public class ThreadSynchronized {
    	public static void main(String[] args) {
    		MyRunnable myRunnable = new MyRunnable();
    		new Thread(myRunnable,"窗口一").start();
    		new Thread(myRunnable,"窗口二").start();
    		new Thread(myRunnable,"窗口三").start();
    	}
    }
    
    class MyRunnable implements Runnable{
    	private int piao = 10;
    	@Override
    	public void run() {
    		while(piao > 0){
    			System.out.println("开始卖票");
    			piao--;
    			System.out.println(Thread.currentThread().getName()+"卖出票:"+piao);
    		}
    	}
    }

    结论:Runnable实现多线程数据共享,是不能保证线程互斥正常执行的,依然要采取措施才能保证,程序的正常执行顺序。

    
    

      

    2,如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,例如,设计4个线程。其中两个线程每次对j增加1,另外两个线程对j每次减1,银行存取款有两种方法来解决此类问题:将共享数据封装成另外一个对象,然后将这个对象逐一传递给各个Runnable对象,每个线程对共享数据的操作方法也分配到那个对象身上完成,这样容易实现针对数据进行各个操作的互斥和通信;将Runnable对象作为一个类的内部类,共享数据作为这个类的成员变量,每个线程对共享数据的操作方法也封装在外部类,以便实现对数据的各个操作的同步和互斥,作为内部类的各个Runnable对象调用外部类的这些方法。

    public class MultiThreadShareData {
    
        public static void main(String[] args) {
    
            ShareData task = new ShareData(); //公共数据和任务放在task中
    
            for(int i = 0; i < 2; i ++) { //开启两个线程增加data
    
                new Thread(new Runnable() {
    
                    @Override
                    public void run() {
                        task.increment();
                    }
                }).start();
            }
    
            for(int i = 0; i < 2; i ++) { //开启两个线程减少data
    
                new Thread(new Runnable() {
    
                    @Override
                    public void run() {
                        task.decrement();
                    }
                }).start();
            }           
        }
    }   
    
    
    class ShareData /*implements Runnable*/ {
    
        private int data = 0;
        public synchronized void increment() { //增加data
            System.out.println(Thread.currentThread().getName() + ": before : " + data);
            data++;
            System.out.println(Thread.currentThread().getName() + ": after : " + data);
        }
    
        public synchronized void decrement() { //减少data
            System.out.println(Thread.currentThread().getName() + ": before : " + data);
            data--;
            System.out.println(Thread.currentThread().getName() + ": after : " + data);
        }
    }
    

    就如上面那个题目所描述的,两个线程执行data增,两个线程执行data减。针对这种情况,我们要实现两个Runnable了,因为很明显有两个不同的任务了,一个任务执行data增,另一个任务执行data减。为了便于维护,可以将两个任务方法放到一个类中,然后将data也放在这个类中,然后传到不同的Runnable中,即可完成数据的共享。

  • 相关阅读:
    Shell变量
    Shell执行脚本
    C++类的默认成员函数
    C# CAD 二次开发(二) -集成开发环境VS2012+CAD2016
    C# CAD 二次开发(一) -前期搜集资料篇
    WPF 学习笔记(十二)
    WPF 学习笔记(十一)
    WPF 学习笔记(十)
    WPF 学习笔记(九)
    WPF 学习笔记(八)
  • 原文地址:https://www.cnblogs.com/aoshicangqiong/p/7751681.html
Copyright © 2011-2022 走看看