java多线程并发------共享变量安全

先看一个多线程卖票的demo

卖票程序  piao

package thread.example.saletickets;

public class piao implements Runnable {
	@Override
	public void run() {
		 int count = 10;
		while (count > 0) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
				if (count > 0) {
					count--;
					System.out.println(Thread.currentThread().getName() + "卖出一张票,票还剩" + count);
			}

		}

	}

} 

测试程序

package thread.example.saletickets;

public class chuangkou {
public static void main(String[] args) {
	piao piao =new piao();
	
	Thread thread1 =new Thread(piao,"窗口1");
	Thread thread2 =new Thread(piao,"窗口2");
	Thread thread3 =new Thread(piao,"窗口3");
	Thread thread4 =new Thread(piao,"窗口4");
	thread1.start();
	thread2.start();
	thread3.start();
	thread4.start();
}  
}

运行结果

窗口4卖出一张票,票还剩9
窗口2卖出一张票,票还剩9
窗口3卖出一张票,票还剩9
窗口1卖出一张票,票还剩9
窗口2卖出一张票,票还剩8
窗口4卖出一张票,票还剩8
窗口1卖出一张票,票还剩8
窗口3卖出一张票,票还剩8
窗口4卖出一张票,票还剩7
窗口2卖出一张票,票还剩7
窗口3卖出一张票,票还剩7
窗口1卖出一张票,票还剩7
窗口4卖出一张票,票还剩6
窗口2卖出一张票,票还剩6
窗口3卖出一张票,票还剩6
窗口1卖出一张票,票还剩6
窗口2卖出一张票,票还剩5
窗口4卖出一张票,票还剩5
窗口3卖出一张票,票还剩5
窗口1卖出一张票,票还剩5
窗口2卖出一张票,票还剩4
窗口4卖出一张票,票还剩4
窗口1卖出一张票,票还剩4
窗口3卖出一张票,票还剩4
窗口1卖出一张票,票还剩3
窗口4卖出一张票,票还剩3
窗口2卖出一张票,票还剩3
窗口3卖出一张票,票还剩3
窗口4卖出一张票,票还剩2
窗口3卖出一张票,票还剩2
窗口1卖出一张票,票还剩2
窗口2卖出一张票,票还剩2
窗口2卖出一张票,票还剩1
窗口4卖出一张票,票还剩1
窗口3卖出一张票,票还剩1
窗口1卖出一张票,票还剩1
窗口2卖出一张票,票还剩0
窗口1卖出一张票,票还剩0
窗口3卖出一张票,票还剩0
窗口4卖出一张票,票还剩0

结果 每个窗口卖出了十张票,所以一共卖出四十张票,不符合业务场景。

为什么会出现这种情况,因为int count = 10;是局部变量,所以每个线程互不干扰,各自初始化10张票。

这里涉及到:类变量和实例变量的区别在于:类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象; 参考文章:https://blog.csdn.net/Mint6/article/details/80876180

下面修改为共享变量,也就是类变量。

修改卖票程序就行,把局部变量int count =10 改为 private static int count = 10;

package thread.example.saletickets;

public class piao implements Runnable {
	private static int count = 10;

	@Override

	public void run() {
		while (count > 0) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
				if (count > 0) {
					count--;
					System.out.println(Thread.currentThread().getName() + "卖出一张票,票还剩" + count);
			}

		}

	}

}

结果  变量是共享了,但是多线程情况下执行混乱,还是不满足场景

窗口3卖出一张票,票还剩7
窗口4卖出一张票,票还剩7
窗口2卖出一张票,票还剩7
窗口1卖出一张票,票还剩7
窗口2卖出一张票,票还剩6
窗口3卖出一张票,票还剩4
窗口4卖出一张票,票还剩5
窗口1卖出一张票,票还剩6
窗口4卖出一张票,票还剩2
窗口2卖出一张票,票还剩0
窗口3卖出一张票,票还剩1
窗口1卖出一张票,票还剩1

把程序修改为同步的,加上同步代码块,让卖票行为是同步的,当一个线程执行时,其他线程等待。

package thread.example.saletickets;

public class piao implements Runnable {
	private static int count = 10;

	@Override

	public void run() {
		while (count > 0) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (this) {
				if (count > 0) {
					count--;
					System.out.println(Thread.currentThread().getName() + "卖出一张票,票还剩" + count);
				}

			}

		}

	}

}

结果正确

窗口3卖出一张票,票还剩9
窗口4卖出一张票,票还剩8
窗口2卖出一张票,票还剩7
窗口1卖出一张票,票还剩6
窗口3卖出一张票,票还剩5
窗口2卖出一张票,票还剩4
窗口4卖出一张票,票还剩3
窗口1卖出一张票,票还剩2
窗口4卖出一张票,票还剩1
窗口3卖出一张票,票还剩0

本节介绍了多线程情况下,类变量会导致的安全问题。

猜你喜欢

转载自blog.csdn.net/mint6/article/details/80871439