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();
}
}
}
显示结果
如图所示,并无出现线程安全问题,程序运行无错误。但是使用同步,虽然提升了安全性,但是也降低了效率。
使用同步函数,锁对象必须是某个对象,可以是任意一个对象。
只有真正影响线程安全时,才使用同步模块,否则会降低效率。