博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程06-多线程共享数据的方式(经验小结)
阅读量:5302 次
发布时间:2019-06-14

本文共 5524 字,大约阅读时间需要 18 分钟。

     1.案例分析-01

      通过代码实现火车票出售的例子

      在实现代码之前先对问题进行分析:火车票出售应该是在多个窗口进行的(即多个线程),以一个车的班次来说,该班次的火车票张数即为多个窗口共享的数据

即这份共享数据为出售特定班次的火车票,这个动作在多个窗口都是不变的,变更的只有火车票的剩余张数.代码实现如下:

package org.lkl.thead;/** *  * Function : 多线程共享数据 *  * @author : Liaokailin CreateDate : 2014-6-13 version : 1.0 */public class MultiThreadShareData {    public static void main(String[] args) {        SellTicket s = new SellTicket(); // 共享对象        new Thread(s, "1").start();        new Thread(s, "2").start();        new Thread(s, "3").start();        new Thread(s, "4").start();        new Thread(s, "5").start();    }}/** * 出售火车票   */class SellTicket implements Runnable {    private int ticket = 100;    @Override    public void run() {        while (true) {            synchronized (SellTicket.class) {            if (ticket > 0) {                                try {                        Thread.sleep(30);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    ticket-- ;                    System.out.println("窗口" + Thread.currentThread().getName()                            + "出售合肥到北京火车票剩余车票" + ticket);                }else{                    break ;                }            }        }    }}

 

   通过上面的代码可以发现,多线程共享的数据是卖火车票,而这个动作在各个线程中都是不变的,因此可以做如下的小结:

   多线程中各个线程执行的代码相同,那么可以使用同一个Runnable对象来实现共享数据。

      2. 案例分析-02

         和上面问题乡对应的是 如果多个线程中执行的代码不同呢? 该如何去处理数据之间的共享?

         例如: 

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

          通过问题可以发现,线程中执行的代码显示是不同的,一个是j++ 一个是j--,在前面我们说过 要同步互斥的代码或者算法应该分别放在独立的方法中,并且这些方法都放在同一个类中,这样子

比较容易实现他们之间的同步互斥和通信

          那么可以设计如下的业务类: 

class Business{    private int j = 0;        public synchronized void increment(){        j++ ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }    public synchronized void decrement(){        j-- ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }}

 

     要实现多个线程的不同操作,可以将不同的操作防止在不同的Runnable中 然后将不同的Runnable对象传递给不同的线程

        

package org.lkl.thead;/** *   设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1  */public class ShareDataFoo {    public static void main(String[] args) {        Business b = new Business() ;        for(int i= 0 ;i<2;i++){            new Thread(new OperatorFoo01(b)).start();            new Thread(new OperatorFoo02(b)).start();                    }            }    }class OperatorFoo01 implements Runnable{    private Business business;    public OperatorFoo01(Business business){        this.business = business ;    }    @Override    public void run() {        business.increment() ;    }}class OperatorFoo02 implements Runnable{    private Business business;    public OperatorFoo02(Business business){        this.business = business ;    }    @Override    public void run() {        business.decrement() ;    }}class Business{    private int j = 0;        public synchronized void increment(){        j++ ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }    public synchronized void decrement(){        j-- ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }}

 

       运行代码得到的结果: 

Thread-0,j=1Thread-1,j=0Thread-2,j=1Thread-3,j=0

 

 

我们可以做个小结:

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

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

和通行 (上面我们的例子就是采用这样的方式)

      2.将这些Runnable对象作为某个类的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作也分配给外部类,以便对共享数据进行的各个操作的互斥和通信,作为内部类的各个

Runnable对象调用外部类的这些方法

      对于第二点同样以上面的例子得到如下代码:

package org.lkl.thead;/** *   设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1  */public class ShareDataFoo2 {    public static void main(String[] args) {        ShareDataFoo2 foo = new ShareDataFoo2() ;                for(int i= 0 ;i<2;i++){            new Thread(foo.new OperAdd()).start();            new Thread(foo.new OperSub()).start();                    }            }        private int j = 0 ;        public synchronized  void increment(){        j++ ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }        public synchronized void decrement(){        j-- ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }     class OperAdd implements Runnable{        @Override        public void run() {            increment() ;        }    }         class OperSub implements Runnable{        @Override        public void run() {            decrement() ;        }    }        }

 

      也可以对上面的两种方法进行组合:

     将共享数据封装到另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象本身上来完成,该对象作为这个外部类中的成员变量或者方法中的局部变量,每个线程的Runnable对象

作为外部类中的成员内部类或局部内部类,如下面代码:

  

package org.lkl.thead;/** *   设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1  */public class ShareDataFoo3 {    public static void main(String[] args) {        ShareDataFoo3 foo = new ShareDataFoo3() ;        for(int i= 0 ;i<2;i++){            new Thread(foo.new OperatorFoo01()).start();            new Thread(foo.new OperatorFoo02()).start();                    }            }    private Business2 business = new Business2() ;    class OperatorFoo01 implements Runnable{             @Override        public void run() {            business.increment() ;        }    }    class OperatorFoo02 implements Runnable{        @Override        public void run() {            business.decrement() ;        }    }        }class Business2{    private int j = 0;        public synchronized void increment(){        j++ ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }    public synchronized void decrement(){        j-- ;        System.out.println(Thread.currentThread().getName()+",j="+j);    }}

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/liaokailin/p/3786320.html

你可能感兴趣的文章
Excel-逻辑函数
查看>>
面对问题,如何去分析?(日报问题)
查看>>
数据分析-业务知识
查看>>
nodejs vs python
查看>>
poj-1410 Intersection
查看>>
Java多线程基础(一)
查看>>
TCP粘包拆包问题
查看>>
Java中Runnable和Thread的区别
查看>>
SQL Server中利用正则表达式替换字符串
查看>>
POJ 1015 Jury Compromise(双塔dp)
查看>>
论三星输入法的好坏
查看>>
Linux 终端连接工具 XShell v6.0.01 企业便携版
查看>>
JS写一个简单日历
查看>>
LCA的两种求法
查看>>
Python 发 邮件
查看>>
mysql忘记密码的解决办法
查看>>
全面分析Java的垃圾回收机制2
查看>>
[Code Festival 2017 qual A] C: Palindromic Matrix
查看>>
修改博客园css样式
查看>>
Python3 高阶函数
查看>>