本文先从一个面试题说起:
设计4个线程,其中两个线程每次对 j +1, 另外两个线程对 j-1,
分析: 这里 j 看作是一个共享数据
从现实例子来看,可以扩展到卖票,假设有100张票, 分5个窗口卖。这个问题也涉及到多线程
解决:
分两种情况
1 如果每个线程执行的代码相同,可以使用同一个Runnable 对象,此Runnable 对象存在共享数据, 如: 卖票程序可以这么做,因为都是执行减少的过程
代码
public class MultiThreadShareData {
public static void main(String[] args) {
ShareData1 data1 = new ShareData1();
new Thread(data1).start();
new Thread(data1).start();
}
class ShareData1 implements Runnable {
private int count = 100;
@Override
public void run() {
while(true){
count--;
}
}
}
注意这里只用了data1 这一个Runnable 对象
2 每个线程执行的代码不同,就需要用不同的Runnable 对象,有两种方式来实现这些Runnable 对象之间的数据共享。
第一种: 将共享数据封装在另外一个对象中,然后将这个对象逐一传递给每个Runnable 对象,每个线程对共享数据的操作方法也分配到那个对象去完成,
代码如下,注意 data1 对象为共享数据
public class MultiThreadShareData {
public static void main(String[] args) {
ShareData1 data1 = new ShareData1();
new Thread(new MyRunnable1(data1)).start();
new Thread(new MyRunnable2(data1)).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++;
}
public synchronized void decrement(){
j--;
}
}
第二种 将这些Runnable 对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,
以便实现对共享数据进行的各个操作的互斥与通信, 作为内部类的每个Runnable 对象调用外部类的这些方法.
代码如下:
public class MultiThreadShareData {
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++;
}
public synchronized void decrement(){
j--;
}
}
一个内部类,如果放在static 方法里,不能访问全局变量, 要访问需要将变量用static 修饰,或者是将变量改为局部变量,用final 修饰
现在回到刚开始的问题, 代码如下:
public class ShareDataTest {
int j = 0;
public static void main(String args[]){
ShareDataTest t = new ShareDataTest();
Inc inc = t.new Inc();
Dec dec = t.new Dec();
/**
* 这里循环表示依次启动两次,每次启动两个线程,
* 一个增加的线程,一个减少的线程
* 这里 对j的增减没有考虑先后顺序
*/
for(int i=0;i<2;i++){
Thread th = new Thread(inc);
th.start();
th = new Thread(dec);
th.start();
}
}
private synchronized void inc(){
j++;
System.out.println(Thread.currentThread().getName()+" inc: "+j);
}
private synchronized void dec(){
j--;
System.out.println(Thread.currentThread().getName()+" dec: "+j);
}
class Inc implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
inc();
}
}
}
class Dec implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
dec();
}
}
}
}
运行效果如下