黑马程序员——线程的安全问题

本文详细分析了Java多线程环境下售票程序中可能遇到的安全问题,包括票数递减导致的同票或负数问题,并介绍了通过同步代码块和同步方法来解决这些问题的方法。重点讨论了同步代码块与同步方法的应用,以及它们在多线程程序中的优势和潜在的性能问题。
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

线程出现安全问题的原因分析

是因为我们通过多个线程对同一数据进行操作时,它的时间片分配是随机的,有可能在票数递减后

线程就将时间片让出,这时其它的线程在执行时,就会在原来票数基础上在递减。

在展示时就会出现同票或负数问题.

这是多线程存在的一些安全问题.

线程安全问题的产生的条件

1. 必须是多线程程序

2. 多个线程操作同一个数据

3. 在操作同一个数据时有多条语句。

同步代码块的方式解决线程案例问题

解决线程安全问题的原理:

在对于有可能产生线程安全的代码,我们进行控制,让线程在执行时,

其它的线程不可以访问,我的线程执行完成后,其它线程才可以使用.

对于我们线程案例问题:可以使用同步来解决.

同步代码块

同步方法

 

同步代码块的格式:

Synchronized(任意一个对象){

可能出现安全问题的代码

}

 

我们在测试程序中使用了同步代码块


<span style="font-size:14px;">package cn.itcast.test;

//售票程序 implements Runnable
//100张速度与激情7票,三个窗口售卖。显示出每一个窗口买的票是什么?
//分析:
//1.定义出100张票

//2.定义窗口做售票操作

//3.有三个窗口来售票---需要三个线程,而线程中要执行的操作就是售票。
public class SellTicketDemo2 implements Runnable {

	private boolean flag = true;
	// 1.定义100张票
	private int ticketNum = 100;
	Object obj = new Object();

	// 2.定义一个售票操作
	public void sellTicket() {
		// 第二个第三个线程在这个位置等待
		synchronized (obj) {
			if (ticketNum > 0) {
			

				// 判断有票才卖
				System.out.println("售出了第" + (ticketNum) + "张票");
				// 将票递减
				try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				ticketNum--;

			} else {
				stopSellTicket();// 停止售票

				// Thread.currentThread().stop();
			}
		}
	}

	@Override
	public void run() {

		while (flag) {
			sellTicket();
		}
	}

	// 停止售票
	public void stopSellTicket() {
		flag = false;
	}
}</span>

同步代码块的锁及同步方法应用和锁的问题

使用同步方法来解决问题

 

同步方法格式 :

在方法的修饰符上使用一个synchronized就可以。

 

public synchronized void sellTicket(){}  这就是一个同步方法.

 

与同步代码块的区别:

它们的原理是一样的,只不过同步代码块可以控制的范围更精确。

而同步方法只是对一个方法时行了同步。

 

问题:同步方法也要使用一个锁,它的锁是什么?

对于同步方法来说,它所使用的锁对象就是this.

注意:这时的同步方法不能是静态的,如果是静态的它的锁又是什么哪?

是本类的Class对象。

 

Java中的Class对象怎样获取?

简单获取方式就是  类名.class

package cn.itcast.test;

//售票程序 implements Runnable
//100张速度与激情7票,三个窗口售卖。显示出每一个窗口买的票是什么?
//分析:
//1.定义出100张票

//2.定义窗口做售票操作

//3.有三个窗口来售票---需要三个线程,而线程中要执行的操作就是售票。

//使用同步方法來解決线程安全问题
public class SellTicketDemo3 implements Runnable {

	private static boolean flag = true;
	// 1.定义100张票
	private static int ticketNum = 100;

	int x = 0;

	// 2.定义一个售票操作 同步方法
	public static synchronized void sellTicket() {

		if (ticketNum > 0) {

			// 判断有票才卖
			System.out.println("售出了第" + (ticketNum) + "张票");
			// 将票递减
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			ticketNum--;

		} else {
			stopSellTicket();// 停止售票

		}

	}

	// 它不是同步方法 在这个方法的同步块中所使用的锁是obj.
	public void sellTicket2() {

		synchronized (SellTicketDemo3.class) {
			if (ticketNum > 0) {

				// 判断有票才卖
				System.out.println("售出了第" + (ticketNum) + "张票");
				// 将票递减
				try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				ticketNum--;

			} else {
				stopSellTicket();// 停止售票

			}
		}
	}

	@Override
	public void run() {

		while (flag) {

			if (x % 2 == 0) {
				sellTicket();
			} else {
				sellTicket2();
			}
			x++;
		}
	}

	// 停止售票
	public static void stopSellTicket() {
		flag = false;
	}
}

同步代码块(和同步方法)解决线程线程案例问题的解释

就是对我们在多线程程序中要操作的共享数据及对其进行操作的语句进行了加锁操作,

简单说,就是一个线程在执行这些代码时,其它的线程不能执行。

同步代码块可以对方法中一部分代码进行加锁。

而同步 方法是将所有的方法内的代码进行了加锁。

同步的特点及好处和弊端 以及同步代码块与同步方法选择

使用一个对象做为锁,所有的线程使用同一个锁,当一个线程使用它时,其它线程等待。

优点:可以解决我们多线程程序的安全问题.

缺点:使用了同步,会降低多线程程序的性能。并且有可能出现死锁问题.

 

同步代码块与同步方法使用哪一个?

同步代码块可以替换同步方法,同步方法不能替代同步代码块,所以在

精度控制上,同步代码块会更好,并且,使用同步代码块的效率也比较高。

所以我们一般选择使用同步代码块。



黑马程序员线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.youkuaiyun.com/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值