上篇博客说到了多线程的创建方式,本篇博客说说自己对于多个线程间的共享变量的理解。
一、概述
首先,分析集中不同的变量共享场景:
1,多个线程执行同样的代码
在这种情况下,可以使用同一个Runnable对象(看上一篇博客,这是一种创建线程的方式)将需要共享的数据,植入这个Runnable对象里面。例如买票系统,余票是需要共享的,不过在这样做的时候,我想还应该加上synchronized关键字修饰!
2,多个线程执行的代码不一样
在这种情况下,就两种思路可以实现(这里参考张孝祥老师的观点)
其一:将共享数据封装再另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现对改数据进行的各个操作的互斥和通信。
其二:将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。
组合:将共享数据封装再另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。(示例代码所使用的方法),总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较好容易实现它们之间的同步互斥通信
3,简单粗暴的方式
在程序中,定义一个static变量
二、代码示例
<span style="font-family:KaiTi_GB2312;font-size:18px;">package Angel; public class MultiThreadShareData { private static ShareData1 data1 = new ShareData1(); public static void main(String[] args) { ShareData1 data2 = new ShareData1(); new Thread(new MyRunnable1(data2)).start();//减 new Thread(new MyRunnable2(data2)).start();//加 final ShareData1 data1 = new ShareData1(); new Thread(new Runnable(){ @Override public void run() { data1.decrement();//减 } }).start(); new Thread(new Runnable(){ @Override public void run() { data1.increment();//加 } }).start(); } } class MyRunnable1 implements Runnable{ private ShareData1 data1; public MyRunnable1(ShareData1 data1){ this.data1 = data1; } public void run() { data1.decrement(); } } class MyRunnable2 implements Runnable{ private ShareData1 data1; public MyRunnable2(ShareData1 data1){ this.data1 = data1; } public void run() { data1.increment(); } } class ShareData1{ private int j = 0; public synchronized void increment(){ j++; System.out.println(j); } public synchronized void decrement(){ j--; System.out.println(j); } }</span>
三、总结
实现共享数据,不只有这个方式,还应该有已经封装好的更为方便的方式,下篇博客接着介绍。在说到这个基础知识点的时候,突然想到了另外一个关于多线程的基本点,就是在使用多线程的时候,我们会常用到wait()和sleep()方法,那么这两种方法到底有什么区别呢?先看一下线程的状态图:
简单说来:sleep()方法是属于Thread类中的。而wait()方法是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。
当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。