Java多线程(线程的同步与锁死)

线程的同步与锁死

同步问题

在多线程处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,于是当多个线程访问同一资源的时候,如果处理不当就会产生数据错误;

同步问题的引出
下面编写一个简单的买票程序,将创建若干个线程对象实现卖票的操作;

范例:实现买票操作

class Mythread implements Runnable{
	private int ticket=10;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true)
		{
			if(this.ticket>0)
			{
				System.out.println(Thread.currentThread().getName()+"卖票、ticket="+this.ticket--);
			}
			else {
				System.out.println("票已经抢光");
				break;
			}
		}	
	}
}
public class ThreadDemo {
	public static void main(String[] args) throws Exception {
		Mythread my=new Mythread();
		new Thread(my,"线程A").start();
		new Thread(my,"线程B").start();
		new Thread(my,"线程C").start();
	}
}

此时线程的三个对象将进行10张票的出售
在这里插入图片描述
程序执行到目前为止还算正常,但是当我们增加休眠操作用来模拟现实中的网络延迟时就会发现问题

class Mythread implements Runnable{
	private int ticket=10;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true)
		{
			if(this.ticket>0)
			{
				try {
					Thread.sleep(100);//增加休眠操作用来模拟网络延迟效果
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"卖票、ticket="+this.ticket--);
			}
			else {
				System.out.println("票已经抢光");
				break;
			}
		}	
	}
}
public class ThreadDemo {
	public static void main(String[] args) throws Exception {
		Mythread my=new Mythread();
		new Thread(my,"线程A").start();
		new Thread(my,"线程B").start();
		new Thread(my,"线程C").start();
	}
}

在这里插入图片描述
可以发现在这个时候居然出现了票数为0,-1的情况,这就是同步问题的引出

对同步问题进行分析

在这里插入图片描述
三个票贩子(三个线程)都对同一块数据进行操作(为方便我们假设这个时候就只有最后一张票了),我们一步一部观察
第一步
在这里插入图片描述
当线程进入时先进行判段是否有票,现在就剩一张票所以第一个线程可以进入,这个时候可能有第二个线程进入但这个时候ticket还是1;

第二步
在这里插入图片描述
用sleep()对网络延迟进行模拟,当第一个线程进入后开始休眠,休眠后开始执行ticket–操作,这个时候可能第二个线程也进入,但是第一个线程可能已经进入第三步;
第三步
在这里插入图片描述
当第一个线程ticket–完成时,第二个线程的已经通过判断也就是说它也可以进入第三步,这个时候票数为0,再进行–操作就变为-1了
在这里插入图片描述

线程同步处理

经过分析我们已经发现了同步问题产生的主要原因了,那么接下来就需要进行同步问题的解决,解决同步问题的关键就是锁

锁:指的就是当某个线程执行操作的时候其他线程外面等待;

在这里插入图片描述
如果想要实现锁的功能,就可以使用synchronized关键字来实现,利用此关键字可以定义同步方法或同步代码块,再同步代码块的操作里面的代码只允许一个线程执行
1.利用同步代码块进行处理

synchronized(同步对象){
同步操作;
}

一般进行同步对象处理的时候可以采取当前对象this进行同步
范例:利用同步代码块解决数据同步访问问题

class Mythread implements Runnable{
	private int ticket=10;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true)
		{
			synchronized (this) {//每一次只允许一个线程通过
				if(this.ticket>0)
				{
					try {
						Thread.sleep(100);//增加休眠操作用来模拟网络延迟效果
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"卖票、ticket="+this.ticket--);
				}
				else {
					System.out.println("票已经抢光");
					break;
				}
			}
		}	
	}
}
public class ThreadDemo {
	public static void main(String[] args) throws Exception {
		Mythread my=new Mythread();
		new Thread(my,"线程A").start();
		new Thread(my,"线程B").start();
		new Thread(my,"线程C").start();
	}
}

在这里插入图片描述

程序可以正常执行,但是加入同步之后程序的整体执行性能下降了。同步实际上会造成性能的降低

2.利用同步方法解决:只需要在方法定义上使用sychronized关键字即可

范例:

class Mythread implements Runnable{
	private int ticket=10;
	public  synchronized boolean sale()
	{
		if(this.ticket>0)
		{
			try {
				Thread.sleep(100);//增加休眠操作用来模拟网络延迟效果
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"卖票、ticket="+this.ticket--);
			return true;
		}
		else {
			System.out.println("票已经抢光");
			return false;
		}
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(this.sale())
		{
			
		}	
	}
}
public class ThreadDemo {
	public static void main(String[] args) throws Exception {
		Mythread my=new Mythread();
		new Thread(my,"线程A").start();
		new Thread(my,"线程B").start();
		new Thread(my,"线程C").start();
	}
}

在这里插入图片描述
同样可以达到同步的效果

线程锁死

造成线程死锁的主要原因是因为彼此都在互相等待着,等待着对方让出资源

范例:线程死锁

public class Deadlock implements Runnable{
	A a=new A();
	B b=new B();
	@Override
	public void run() {
		// TODO Auto-generated method stub
		a.say(b);
	
	}
	public Deadlock(){
		new Thread(this).start();
		b.say(a);
	}
	public static void main(String[] args) {
		new Deadlock();
	}
}

class A{
	public synchronized void say(B b) {
		System.out.println("A:想要通过就要先给钱");
		b.get();
	}
	public synchronized void get() {
		System.out.println("A:你给我钱了,可以让你通过");
	}
}
class B{
	public synchronized void say(A a)
	{
		System.out.println("B:我必须要先过去才能给你钱");
		a.get();
	}
	public synchronized void get()
	{
		System.out.println("B:我通过了,可以给你钱");
	}
}

在这里插入图片描述
在这里插入图片描述
发现程序一直锁死在这里一直运行但没有输出get()内的语句

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

样子的木偶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值