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