上篇博客说到了多线程的创建方式,本篇博客说说自己对于多个线程间的共享变量的理解。
一、概述
首先,分析集中不同的变量共享场景:
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()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。