java [26] 线程安全

多线程并发,给变成带来很多好处,可以完成更多有效率的程序,但是也会带来线程安全的问题。

举例。3个售票窗口同时售卖2000张票;


/*演示使用线程的注意事项
 * 
 * 
 * 
 * */

package tank2;

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//定义3个售票窗口
		TicketWindow tw1 = new TicketWindow();
		//TicketWindow tw2 = new TicketWindow();
		//TicketWindow tw3 = new TicketWindow();
		Thread t1 = new Thread(tw1);
		Thread t2 = new Thread(tw1);
		Thread t3 = new Thread(tw1);
		t1.start();
		t2.start();
		t3.start();
	}

}


//售票窗口类 
class TicketWindow implements Runnable{
	private int nums =2000;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			//if else 语句需要保持原子性(同步代码块)
			//synchronized (this) {
				
			 
				//先判断是否还有票 
				if (nums >0) {
					//一秒出一张
					try {
						Thread.sleep(1000);
					} catch (Exception e) {
						// TODO: handle exception
					}
					//Thread.currentThread().getName()
					//当前线程的名字
					System.out.println(Thread.currentThread().getName()+"正在售出第" + nums +"张票");
					nums--;
				} else {
					//售票结束
					break;
				}
			//}
		}
		
	}
}

执行结果:

Thread-0正在售出第2000张票
Thread-1正在售出第2000张票
Thread-2正在售出第1998张票
Thread-1正在售出第1997张票
Thread-0正在售出第1997张票
Thread-2正在售出第1995张票
Thread-0正在售出第1994张票
Thread-1正在售出第1994张票

碰到这种情况:同一张票被多个售票窗口出售,惹祸的代码就是:

if (nums >0) {
	//一秒出一张
	try {
		Thread.sleep(1000);
	} catch (Exception e) {
	// TODO: handle exception
	}
	//Thread.currentThread().getName()
	//当前线程的名字
	1.System.out.println(Thread.currentThread().getName()+"正在售出第" + nums +"张票");
	2.nums--;

当a线程在执行1语句时,正要执行2语句时,b线程开始执行这时候num还没有被减1,导致同一张票出现多次售卖的情况。

解决这个问题的关键性就是要保证容易出问题的代码的原子性:所谓的原子性就是指当a线程在执行某段代码的时候,别的线程必须要等到a线程执行完后,别的线程才能开始执行这段代码。类似将对象上锁 ,需要释放锁后才能被别的线程引用。

通过synchronized (object) {容易出问题的代码}来实现


/*演示使用线程的注意事项
 * 
 * 
 * 
 * */

package tank2;

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//定义3个售票窗口
		TicketWindow tw1 = new TicketWindow();
		//TicketWindow tw2 = new TicketWindow();
		//TicketWindow tw3 = new TicketWindow();
		Thread t1 = new Thread(tw1);
		Thread t2 = new Thread(tw1);
		Thread t3 = new Thread(tw1);
		t1.start();
		t2.start();
		t3.start();
	}

}


//售票窗口类 
class TicketWindow implements Runnable{
	private int nums =2000;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			//if else 语句需要保持原子性(同步代码块)
			synchronized (this) {
				
			 
				//先判断是否还有票 
				if (nums >0) {
					//一秒出一张
					try {
						Thread.sleep(1000);
					} catch (Exception e) {
						// TODO: handle exception
					}
					//Thread.currentThread().getName()
					//当前线程的名字
					System.out.println(Thread.currentThread().getName()+"正在售出第" + nums +"张票");
					nums--;
				} else {
					//售票结束
					break;
				}
			}
		}
		
	}
}

这样就能保证线程之间数据的安全。

猜你喜欢

转载自blog.csdn.net/qq_38125626/article/details/81512209
今日推荐