Java学习--多线程中synchronized的使用心得

今天写一个多线程同步代码快的程序时,出现意料之外的执行结果,代码如下:

package com.drz.xianchengmaipiao;

/**
 * 1.写一个卖票的程序。 ①
 * 写一个类,该类实现了Runnable接口。有一个私有类型的int型的参数:tickets。票的总数,为100,完成run方法,输出结果的格式如下:
 * 当前窗口为:窗口a ,剩余的票数为:19,其中窗口a为线程的名称。 ② 开启四个卖票窗口(起四个线程),同时执行卖票的程序。 ③
 * 
 * @author drz
 * 
 */
public class MaiPiao implements Runnable {
	private static int tickets;
	private String wins;

	public MaiPiao(String wins) {
		this.wins = wins;
	}

	private synchronized void sellTic() {

		if (tickets > 0) {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			tickets--;
			System.out.println("窗口" + wins + ",剩余票数为:" + tickets);
		}

	}

	public MaiPiao() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		MaiPiao.tickets = 100;
		for (int i = 1; i <= 4; i++) {
			new Thread(new MaiPiao(i + "")).start();
		}
	}

	@Override
	public void run() {
		while (tickets > 0)
			sellTic();
	}

	public String getWins() {
		return wins;
	}

	public void setWins(String wins) {
		this.wins = wins;
	}

}
执行结果如下:省略了前面的结果输出,只保留了最后几行

窗口3,剩余票数为:8
窗口1,剩余票数为:7
窗口2,剩余票数为:5
窗口4,剩余票数为:5
窗口3,剩余票数为:4
窗口2,剩余票数为:1
窗口1,剩余票数为:1
窗口4,剩余票数为:1
窗口3,剩余票数为:0
窗口1,剩余票数为:-3
窗口2,剩余票数为:-3
窗口4,剩余票数为:-3

执行时特点是一次输出四行,就是四个线程一块睡一块醒,数据还有重复。最后分析原因是:synchronized加在实例方法上,而操作的共享数据是static的类变量,作为锁的对象是当前调用这个方法的对象,也可以认为是this,所以new出的四个对象各不同,也就是说四个线程加的不是同一个锁,等于没加锁,所以没有实现同步,四个线程还是各玩各的。至于四个线程一块睡一块醒就很好解释了,是因为循环启动四个线程几乎同时,而他们又使用不同的锁,

所以进行改进:

synchronized不加在方法上了,对方法里面的全部代码加到同步代码快中,且使用类名.class作为同步锁。


注:run方法中while循环判断是不能写进同步代码快的,否则就等同一个单线程的程序了。

package com.drz.xianchengmaipiao;

/**
 * 1.写一个卖票的程序。 ①
 * 写一个类,该类实现了Runnable接口。有一个私有类型的int型的参数:tickets。票的总数,为100,完成run方法,输出结果的格式如下:
 * 当前窗口为:窗口a ,剩余的票数为:19,其中窗口a为线程的名称。 ② 开启四个卖票窗口(起四个线程),同时执行卖票的程序。 ③
 * 
 * @author drzwin32
 * 
 */
public class MaiPiao implements Runnable {
	private static int tickets;
	private String wins;

	public MaiPiao(String wins) {
		this.wins = wins;
	}

	private  void sellTic() {
		synchronized(MaiPiao.class){
			if (tickets > 0) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				tickets--;
				System.out.println("窗口" + wins + ",剩余票数为:" + tickets);
			}
		}
		

	}

	public MaiPiao() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		MaiPiao.tickets = 100;
		for (int i = 1; i <= 4; i++) {
			new Thread(new MaiPiao(i + "")).start();
		}
	}

	@Override
	public void run() {
		while (tickets > 0)
			sellTic();
	}

	public String getWins() {
		return wins;
	}

	public void setWins(String wins) {
		this.wins = wins;
	}

}
执行结果如下:

窗口2,剩余票数为:18
窗口3,剩余票数为:17
窗口3,剩余票数为:16
窗口3,剩余票数为:15
窗口3,剩余票数为:14
窗口3,剩余票数为:13
窗口3,剩余票数为:12
窗口3,剩余票数为:11
窗口3,剩余票数为:10
窗口3,剩余票数为:9
窗口3,剩余票数为:8
窗口3,剩余票数为:7
窗口3,剩余票数为:6
窗口4,剩余票数为:5
窗口1,剩余票数为:4
窗口1,剩余票数为:3
窗口1,剩余票数为:2
窗口4,剩余票数为:1
窗口4,剩余票数为:0



你可能感兴趣的:(java,多线程,synchronized)