Java多线程(7):并发_线程同步_队列与锁(Synchronized)

一、并发举例(线程不安全)

1、两个人同时操作一张银行卡,如何保证线程安全。
2、多个人同时购买一张火车票,谁能买到?

二、并发特点

1、同一个对象
2、被多个线程操作
3、同时操作

三、如何保证线程安全:线程同步(队列+锁)

1、使用队列的技术一个一个对资源进行操作,并通过一定算法决定谁先使用,例如一个班级只有一台电脑,那么排队一个一个操作。
2、对象的锁:如果当前资源被占用则锁上。

四、线程同步方法

1、synchronized关键字包括两种用法:synchronized方法和synchronized
2、synchronized方法:若将一个大的方法声明为synchronized将会大大影响效率,比如一个方法内两个属性A和B,A属性提供只读功能,B属性可修改需要锁住,那么如果一个方法都设置为synchronized则A也无法访问则影响了效率。方法锁

	public class Synchronized {
		public static void main(String[] args) {
			
			SafeWeb12306 safe = new SafeWeb12306();
			new Thread(safe,"bull1").start();
			new Thread(safe,"bull2").start();
			new Thread(safe,"bull3").start();
		}
	}
	
	
	class SafeWeb12306 implements Runnable{
		
		private int ticketNum = 10;
		private boolean flag = true;
		
		@Override
		public void run() {
			while(flag) {
				test();
				
			}
			
		}
		
		
		public synchronized void test() {
			if(ticketNum<=0) {
				flag = false;
				return;
			}
			
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"-->"+(ticketNum--));
		}
	}

3、synchronized块可以只锁住一部分。下面的例子直接锁住账户而不是锁住方法,这里的方法就相当于取款机,锁住取款机是没用的,只能锁住账户。
synchronized块的表示方法:

synchronized(object){}
	public class Synchronized2 {
	
	
	public static void main(String[] args) {
		Account account = new Account(1000,"结婚礼金");
		Drawing me = new Drawing(account,80,"自己");
		Drawing you = new Drawing(account,90,"媳妇儿");
		new Thread(me,"自己").start();
		new Thread(you,"媳妇儿").start();
	}
}


class Account{
	int money;
	String name;
	 public Account(int money,String name) {
		this.money = money;
		this.name = name;
	}
	 
}


class Drawing implements Runnable{
	
	Account account ;
	int drawMoney;
	int pocketMoney=0;
	@Override
	public void run() {
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		test();
	}
	
	
	public Drawing(Account account,int drawMoney,String name) {
		// TODO 自动生成的构造函数存根

		this.account = account;
		this.drawMoney = drawMoney;
		
	}
	
	
	
	public  void test() {
		//非常重要的一个判断,可以提高效率
		if(account.money<=0) {
			return;
		}
		
		
		synchronized (account) {
			if(account.money-drawMoney<0) {
				System.out.println(Thread.currentThread().getName()+"取钱余额不足");
				return;
			}
			
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			
			account.money -= drawMoney;
			pocketMoney += drawMoney;
			
			System.out.println(Thread.currentThread().getName()+"账户里还剩-->"+account.money);
			System.out.println(Thread.currentThread().getName()+"口袋里还有-->"+pocketMoney);
		}
		
	}
}

五、同步块

1、synchronized (obj){}:其中obj称为同步监视器。
2、同步方法中无需指定同步监视器,因为同步方法的同步监视器是this即该对象本身,或class即类的模子。
3、同步监视器的执行过程:
(1)第一个线程访问时,锁定同步监视器,执行其中代码。
(2)第二个线程访问,发现同步监视器被锁定,无法访问。
(3)第一个线程访问完毕,解锁同步监视器。
(4)第二个线程访问发现同步监视器未锁定,锁定并访问。
4、要锁住不变的对象,时刻在变的属性之类的东西不能锁

六、同步块模拟抢票

	public class SynWeb12306 {
		public static void main(String[] args) {
			Ticket ticket = new Ticket();
			new Thread(ticket,"bull1").start();
			new Thread(ticket,"bull2").start();
			new Thread(ticket,"bull3").start();
			new Thread(ticket,"bull4").start();
			new Thread(ticket,"bull5").start();
		}
		
	}
	
	
	class Ticket implements Runnable{
		private int ticketNum = 30;
		private boolean flag = true;
		
		@Override
		public void run() {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			while(flag) {
				test();
			}
			
		}
		
		public  void test() {
			
			synchronized (this) {					//锁住对象本身,如果只锁定ticketNum不行,因为他一直在变,锁定不变的东西
				if(ticketNum<=0) {
					flag = false;
					return;
				}
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"-->"+ticketNum--);
			}
			
		}
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coder鹏鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值