关于Java多线程---------(3,同步与死锁)

在多线程的开发中,同步与死锁是非常重要的,那么问题来了,对于这两个东西,需要思考几个问题。
1,代码的什么地方需要同步;2,如何实现同步;3,实现同步之后有哪些副作用。

1,问题的出现,为什么要有同步?(什么是同步,为什么要有同步)

举个例子来说,卖火车票,售卖火车票会有多个售票站点,一趟火车的座位数是固定的,把各个售票点就可以理解为各个线程,也就是说,所有的线程共同拥有同一份的票源,同时不能一个席位卖两张票出去。

class MyThread implements Runnable{
	private int ticket = 5 ;	// 假设一共有5张票
	public void run(){
		for(int i=0;i<100;i++){
			if(ticket>0){	// 还有票
				System.out.println("卖票:ticket = " + ticket-- );
			}
		}
	}
};
public class SyncDemo01{
	public static void main(String args[]){
		MyThread mt = new MyThread() ;	// 定义线程对象
		Thread t1 = new Thread(mt) ;	// 定义Thread对象
		Thread t2 = new Thread(mt) ;	// 定义Thread对象
		Thread t3 = new Thread(mt) ;	// 定义Thread对象
		t1.start() ;
		t2.start() ;
		t3.start() ;
	}
};

这里写图片描述

在实际情况中,票务信息是存储在数据库中的,从数据库中读取信息,通过网络显示在售票设备上,这个过程中,肯定是存在时间延迟的,

class MyThread implements Runnable{
	private int ticket = 5 ;	// 假设一共有5张票
	public void run(){
		for(int i=0;i<100;i++){
			if(ticket>0){	// 还有票
				try{
					Thread.sleep(300) ;	// 加入延迟
				}catch(InterruptedException e){
					e.printStackTrace() ;
				}
				System.out.println("卖票:ticket = " + ticket-- );
			}
		}
	}
};
public class SyncDemo01{
	public static void main(String args[]){
		MyThread mt = new MyThread() ;	// 定义线程对象
		Thread t1 = new Thread(mt) ;	// 定义Thread对象
		Thread t2 = new Thread(mt) ;	// 定义Thread对象
		Thread t3 = new Thread(mt) ;	// 定义Thread对象
		t1.start() ;
		t2.start() ;
		t3.start() ;
	}
};

这里写图片描述

发现,坏了,卖出的票数有负数了,代码出问题了呀。。。。这个情况他到底是怎么回事呢?为什么加入延迟就出现这个问题了呢?

分析一下这个问题:
这里写图片描述

这里写图片描述

好气哦~~~写出来代码是为了解决实际问题,不是过家家闹着玩的,实际情况中,就是会有各种复杂的情况,就会出现网络不畅通的情况,总不能不让延迟出现呀。。。。

那么这个在有延迟的情形下,如何完美的解决这个买票问题呢?
这里写图片描述

2,同步解决问题:(同步的作用)

解决资源共享的同步操作问题,可以使用同步代码块以及同步方法两种方式进行完成。

代码块分为4种:
普通代码块:是直接定义在方法之中的;
构造快:是直接定义的类中对的;(优先于构造方法执行,会重复调用)
静态块:是使用static关键字声明的,(优先于构造快执行,只执行一次)
同步代码块:是使用synchronized关键字声明的代码块,称为同步代码块;

同步代码块解决问题

这里写图片描述
同步的时候,必须指明同步的对象,一般情况下,会将当前对象作为同步的对象,使用this表示。

class MyThread implements Runnable{
	private int ticket = 5 ;	// 假设一共有5张票
	public void run(){
		for(int i=0;i<100;i++){
			synchronized(this){	// 要对当前对象进行同步
				if(ticket>0){	// 还有票
					try{
						Thread.sleep(300) ;	// 加入延迟
					}catch(InterruptedException e){
						e.printStackTrace() ;
					}
					System.out.println("卖票:ticket = " + ticket-- );
				}
			}
		}
	}
};
public class SyncDemo02{
	public static void main(String args[]){
		MyThread mt = new MyThread() ;	// 定义线程对象
		Thread t1 = new Thread(mt) ;	// 定义Thread对象
		Thread t2 = new Thread(mt) ;	// 定义Thread对象
		Thread t3 = new Thread(mt) ;	// 定义Thread对象
		t1.start() ;
		t2.start() ;
		t3.start() ;
	}
};

这里写图片描述

从运行结果可以发现,成功加入了同步操作,所以不会产生负数的情况,但是程序执行的效率明显降低很多,没有加上同步操作的时候,是异步执行的,异步执行明显速度更快。

同步方法解决问题

这里写图片描述

class MyThread implements Runnable{
	private int ticket = 5 ;	// 假设一共有5张票
	public void run(){
		for(int i=0;i<100;i++){
			this.sale() ;	// 调用同步方法
		}
	}
	public synchronized void sale(){	// 声明同步方法
		if(ticket>0){	// 还有票
			try{
				Thread.sleep(300) ;	// 加入延迟
			}catch(InterruptedException e){
				e.printStackTrace() ;
			}
			System.out.println("卖票:ticket = " + ticket-- );
		}

	}
};
public class SyncDemo03{
	public static void main(String args[]){
		MyThread mt = new MyThread() ;	// 定义线程对象
		Thread t1 = new Thread(mt) ;	// 定义Thread对象
		Thread t2 = new Thread(mt) ;	// 定义Thread对象
		Thread t3 = new Thread(mt) ;	// 定义Thread对象
		t1.start() ;
		t2.start() ;
		t3.start() ;
	}
};

这里写图片描述

3,同步的副作用----死锁

1,资源共享时,需要进行同步操作(解决延时导致的问题);
2,如果同步过度,会产生死锁的现象;
这里写图片描述

死锁一般情况下就是表示表示互相等待,是在程序运行时出现的一种问题。
###举个例子,将上面张三李四的例子实现代码:

class Zhangsan{	// 定义张三类
	public void say(){
		System.out.println("张三对李四说:“你给我画,我就把书给你。”") ;
	}
	public void get(){
		System.out.println("张三得到画了。") ;
	}
};
class Lisi{	// 定义李四类
	public void say(){
		System.out.println("李四对张三说:“你给我书,我就把画给你”") ;
	}
	public void get(){
		System.out.println("李四得到书了。") ;
	}
};
public class ThreadDeadLock implements Runnable{
	private static Zhangsan zs = new Zhangsan() ;		// 实例化static型对象
	private static Lisi ls = new Lisi() ;		// 实例化static型对象
	private boolean flag = false ;	// 声明标志位,判断那个先说话
	public void run(){	// 覆写run()方法
		if(flag){
			synchronized(zs){	// 同步张三
				zs.say() ;
				try{
					Thread.sleep(500) ;
				}catch(InterruptedException e){
					e.printStackTrace() ;
				}
				synchronized(ls){
					zs.get() ;
				}
			}
		}else{
			synchronized(ls){
				ls.say() ;
				try{
					Thread.sleep(500) ;
				}catch(InterruptedException e){
					e.printStackTrace() ;
				}
				synchronized(zs){
					ls.get() ;
				}
			}
		}
	}
	public static void main(String args[]){
		ThreadDeadLock t1 = new ThreadDeadLock() ;		// 控制张三
		ThreadDeadLock t2 = new ThreadDeadLock() ;		// 控制李四
		t1.flag = true ;
		t2.flag = false ;
		Thread thA = new Thread(t1) ;
		Thread thB = new Thread(t2) ;
		thA.start() ;
		thB.start() ;
	}
};

这里写图片描述
以上就是死锁的操作状态,都是在相互等待着地方的回答。

总结:

1,多个线程在访问同一资源的时候,需要进行同步操作;
2,同步使用synchronized关键字完成;
3,同步分为,同步代码块和同步方法;
4,过多的同步有可能造成死锁,死锁是程序在运行时的一种表现状态;

①同步的原因是为了解决延迟可能导致的访问同一资源导致的问题;
②过多的同步同样导致了死锁的问题,这个死锁的问题,同样是因为延迟导致的
---------所以,从根本上来说,如果是网络服务,提高网速是根本的解决办法,
人类也是一直致力于4g,5g,8g,的研究呀,如果是本地服务来说,提高硬件执行效率,提高并发效率是关键-------双核CPU,四核CPU,i3,i7,i9系列的CPU,厉害了呀,,,,,人类的智慧简直是无穷的呀。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值