在 Java 传统线程机制中的共享数据方式,大致可以简单分两种情况:
➢ 多个线程行为一致,共同操作一个数据源。也就是每个线程执行的代码相同,可以使用同一个 Runnable 对象,这个 Runnable 对象中有那个共享数据,例如,卖票系统就可以这么做。
➢ 多个线程行为不一致,共同操作一个数据源。也就是每个线程执行的代码不同,这时候需要用不同的Runnable 对象。例如,银行存取款。
实例1:多个线程行为一致共同操作一个数据
如果每个线程执行的代码相同,可以使用同一个 Runnable 对象,这个 Runnable 对象中有那个共享数据,例如,买票系统就可以这么做。
package com.itheima.gan;
//买票系统
//共享数据类 class ShareDate{ private int num=10; //10张票 public synchronized void inc() { num++; System.out.println(Thread.currentThread().getName()+ ": invoke inc method num="+num); try { //线程休眠1s Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 多线程类 * @author 12428 * */ public class RunnableCusToInc implements Runnable{ private ShareDate shareDate; //构造方法,将数据传递进去 public RunnableCusToInc(ShareDate shareDate) { this.shareDate=shareDate; } //线程应该做的事 @Override public void run() { for(int i=0;i<5;i++) { shareDate.inc(); } } public static void main(String[] args) { ShareDate shareDate=new ShareDate(); for(int i=0;i<4;i++) { new Thread(new RunnableCusToInc(shareDate),"线程"+i).start(); } } }
实例2:多个线程行为不一致共同操作一个数据
如果每个线程执行的代码不同,这时候需要用不同的 Runnable 对象,有如下两种方式来实现这些 Runnable 对象之间的数据共享(1)将共享的数据放到一个对象中,在把这个对象逐一传递给各个Runnable对象,每个线程对该数据的操作也放在这个对象的不同方法中,这样说实现容易针对对该数据进行的各个操作的互斥和通信。
package com.itheima.gan; class RunnableCusToDec implements Runnable { private ShareDate1 shareDate; public RunnableCusToDec(ShareDate1 shareDate) { this.shareDate = shareDate; } @Override public void run() { for (int i = 0; i < 5; i++) { shareDate.dec(); } } } public class RunnableCusToInc2 implements Runnable { private ShareDate1 shareDate; public RunnableCusToInc2(ShareDate1 shareDate) { this.shareDate = shareDate; } @Override public void run() { for (int i = 0; i < 5; i++) { shareDate.inc(); } } public static void main(String[] args) { ShareDate1 shareDate1=new ShareDate1(); for(int i=0;i<4;i++) { if(i%2==0) { new Thread(new RunnableCusToInc2(shareDate1),"Thread"+i).start(); }else { new Thread(new RunnableCusToDec(shareDate1),"Thread"+i).start(); } } } } /* * 共享数据类 */ class ShareDate1 { private int num = 10; public synchronized void inc() { num++; System.out.println(Thread.currentThread().getName() + ": invoke inc method num=" + num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void dec() { num--; System.err.println(Thread.currentThread().getName() + ": invoke dec method num =" + num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果如图:
(2)将这些 Runnable 对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable 对象调用外部类的这些方法。
package com.itheima.gan; public class RunnableTest { public static void main(String[] args) { //公共数据 final ShareDate2 shareDate=new ShareDate2(); for(int i=0;i<4;i++) { if(i%2==0) { new Thread(new Runnable() { @Override public void run() { for(int i=0;i<5;i++) { shareDate.inc(); } } },"Thread "+i).start(); }else { new Thread(new Runnable() { @Override public void run() { for(int i=0;i<5;i++) { shareDate.dec(); } } }).start(); } } } } //公共数据类 class ShareDate2{ private int num=10; public synchronized void inc() { num++; System.err.println(Thread.currentThread().getName()+" : invoke inc method num = "+num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void dec() { num--; System.out.println(Thread.currentThread().getName()+" : invoke dec method num = "+num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果如图: