synchronized之使用同步代码块,同步函数以及ReentrantLock解决多线程卖票安全问题

synchronized之使用同步代码块,同步函数以及ReentrantLock解决多线程卖票安全问题

synchronized使用原因

由于在多线程使用时,多个线程同时访问共享资源会出现线程安全问题,对于多线程的操作,为了保证各个线程之间共享资源的安全,synchronize同步代码块就起到了关键性的作用。下面是使用用例以及源代码。

使用synchronized同步代码块解决多线程卖票安全问题

public class SellTickes implements Runnable {
	private int tickes = 100;
	private Object lock = new Object();
	@Override
	public void run() {
		while (true) {
			try {
				// 睡眠1000毫秒
				Thread.sleep(1000*1);
			} catch (InterruptedException e) {
				// 如有报错,显示报错
				System.out.println(e.toString());
			}
			synchronized (lock) {
				if (tickes == 0) {
					System.out.println("卖完了.....");
					break;
				}
				// Thread.currentThread()得到当前对象 .getName()获取当前对象名称
				System.out.println(Thread.currentThread().getName() + "   正在卖第      " + tickes + "  张票");
				tickes--;
				
			}
		}
	}
}


public class Test01 {
	public static void main(String[] args) {	
		SellTickes sellTickes = new SellTickes();
		
		Thread thread1 = new Thread(sellTickes, "窗口一");
		Thread thread2 = new Thread(sellTickes, "窗口2");
		Thread thread3 = new Thread(sellTickes, "窗口三");
		
		thread1.start();
		thread2.start();
		thread3.start();
		
	}
}

显示结果:

在这里插入图片描述

使用同步函数解决多线程卖票安全问题

public class SellTickes implements Runnable {
	private int tickes = 100;
	private Object lock = new Object();
	@Override
	public void run() {
	while(true){
		sellTickes();
		}
	}
	private synchronized void sellTickes() {
	
			try {
				// 睡眠1000毫秒
				Thread.sleep(1000*1);
			} catch (InterruptedException e) {
				// 如有报错,显示报错
				System.out.println(e.toString());
			}
			synchronized (lock) {
				if (tickes == 0) {
					System.out.println("卖完了.....");
					break;
				}
				// Thread.currentThread()得到当前对象 .getName()获取当前对象名称
				System.out.println(Thread.currentThread().getName() + "   正在卖第      " + tickes + "  张票");
				tickes--;
				
			}
	}
}

使用ReentrantLock解决多线程卖票安全问题(此方法可以更加有效直观地看到哪里加了锁,哪里释放锁)

public class SellTickes implements Runnable {
	private int tickes = 100;
	boolean isTickes = true;
	Lock lock = new ReentrantLock();

	@Override
	public void run() {
		while (isTickes) {
			// 加锁
			lock.lock();
			if (tickes == 0) {
				isTickes = false;
				System.out.println("卖完了.....");
				lock.unlock();
				break;
			}
			// Thread.currentThread()得到当前对象 .getName()获取当前对象名称
			System.out.println(Thread.currentThread().getName() + "   正在卖第      " + tickes + "  张票");
			tickes--;
			// 释放锁资源
			lock.unlock();
		}
	}
}

显示结果
在这里插入图片描述
如图所示,并无出现线程安全问题,程序运行无错误。但是使用同步,虽然提升了安全性,但是也降低了效率。
使用同步函数,锁对象必须是某个对象,可以是任意一个对象。
只有真正影响线程安全时,才使用同步模块,否则会降低效率。

猜你喜欢

转载自blog.csdn.net/weixin_47405768/article/details/107742069