多线程概述(2)

本文主要讨论了多线程安全问题,特别是在Java中。安全问题常常由于多个线程操作共享资源引起,可能导致数据异常,如重复售票或负数票号。加入同步可以解决这些问题,但会牺牲性能,因为每个线程都需要进行锁判断。同步应用时需要注意确保多个线程使用同一把锁,以确保正确同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程概述(2)

4.多线程安全问题

(1)安全问题的发生

在售票案例中,极有可能碰到的“意外”情况,比如一张同样的票被打印多次,或者打印的票号为0甚至是负数,这些情况都是由多线程操作共享资源所导致的线程安全问题。

例如

class Ticket implements Runnable
{
	private int tickets = 100;//共有100张票
	public void run()
	{
		while(true)
		{
			if(tickets>0)
			{
				try{
					Thread.sleep(10);//模拟了售票耗时过程。
				} catch(InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"正在发售第"+tickets--+"张票");//
			}
		}
	}
}
class Demo
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		//创建并开启了4个线程,模拟同时售票
		new Thread(t,"窗口1").start();
		new Thread(t,"窗口2").start();
		new Thread(t,"窗口3").start();
		new Thread(t,"窗口4").start();
	}
}

在这里插入图片描述

问题产生的原因:

  1. 线程任务中在操作共享的数据。
  2. 线程任务操作共享数据的代码有多条(运算有多个)。

(2)加入同步的好处和缺点

好处:可以解决多线程安全问题

缺点:降低了程序的性能。每个线程都要去判断锁机制,那么会增加程序运行的负担,同时只要做判断,CPU都要处理,那么也会消耗CPU的资源。即就是加同步会降低程序的性能。

举例

class Ticket implements Runnable
{
	private int tickets = 100;
	//定义同步代码块的标记对象。相当与锁的功能
	//private Object obj = new Object();
	public void run()
	{
		while(true)
		{
			//使用同步代码块解决线程安全问题。
			synchronized(new Object())
			{
				if(tickets>0)
				{	//由于run方法是复写接口中的,run方法没有抛出异常, 此时这里只能捕获异常,而不能抛出
                try{Thread.sleep(10);}catch(InterruptedException e){
                
                }
					System.out.println(Thread.currentThread().getName()+"正在发售第"+tickets--+"张票");
				}
			}
		}
	}
}

多个线程操作了共享数据,并且操作共享数据的代码有多句,必须使用同步代码块来解决,当线程任务代码只会有一个线程执行时,加不加同步都可以。当线程任务代码会有被多个线程执行时,这时需要加同步,但是加同步时一定要保证多个线程使用的是同一把锁。上述代码发生的安全问题就是因为每个线程都有自己的Object对象作为自己的锁。

同步的前提:必须保证多个线程在同步中使用的是同一个锁。

(3)多线程问题的应用

class Demo
{
	public static void main(String[] args) 
	{
		Bank bank = new Bank();
		Consumer cons1 = new Consumer(bank);
		Consumer cons2 = new Consumer(bank);
		Thread t1 = new Thread(cons1);
		Thread t2 = new Thread(cons2);
		t1.start();
		t2.start();
	}
}
class Bank
{
	//sum代表银行
	private int sum ;
	//定义同步的锁对象
	private Object obj = new Object();
	//给银行存钱
	public void add(int num)
	{
		//加同步解决安全问题
		synchronized(obj)
		{
		sum = sum + num;
		//显示银行中总钱数
		System.out.println("银行中的钱有:"+sum);
		}
	}
}
//描述储户,每个用户都会给银行中存放钱,存钱这个行为应该是要被多个线程操作
class Consumer implements Runnable 
{
	private Bank bank ;
	Consumer(Bank bank)
	{
		this.bank = bank;
	}
	//多线程要操作的存储钱的过程
	public void run()
	{
		//循环三次,每次存放100元
		for (int i=1;i<=3 ;i++ )
		{
			bank.add(100);
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值