import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程安全知识学习
*/
@Slf4j
public class ThreadUnSecurity {
//声明火车票的数量
static int tickets = 10;
//线程
public class SellTickets implements Runnable{
@Override
public void run() {
while (tickets > 0) {
//第一:没有加入线程安全模式
// System.out.println(Thread.currentThread().getName()+"--->售出第{"+tickets+"}票");
// tickets--;
//
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e){
// e.printStackTrace();
// }
//第二:线程安全方式①:同步代码块
// synchronized (this){
// System.out.println(this.getClass().getName().toString());
// if(tickets < 0){
// return;
// }
// System.out.println(Thread.currentThread().getName()+"--->售出第{"+tickets+"}票");
// tickets--;
// try {
// Thread.sleep(1000);
// }catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
//第三:线程安全方式②:同步方法
while (tickets > 0) {
//调用线程同步方法
synMethod();
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
} finally {
}
}
}
if(tickets < 0){
System.out.println(Thread.currentThread().getName()+"--->售票结束");
}
}
//线程同步方法
private void synMethod() {
synchronized (this){
this.notify();
if(tickets <=0){
return;
}
System.out.println(Thread.currentThread().getName()+"---->售出第 "+tickets+" 票 ");
tickets-- ;
}
}
}
//第三种 方式Lock锁机制, 通过创建Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块
public class SellTickets2 implements Runnable {
Lock lock = new ReentrantLock();
@Override
public void run() {
while (tickets > 0) {
try {
//使用Lock 锁
lock.lock();
if (tickets <= 0) {
return;
}
System.out.println(Thread.currentThread().getName() + "--->售出第: " + tickets + " 票");
tickets--;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (tickets < 0) {
System.out.println(Thread.currentThread().getName() + "--->售票结束");
}
}
}
public static void main(String[] args) {
//SellTickets sell = new ThreadUnSecurity().new SellTickets();
SellTickets2 sell = new ThreadUnSecurity().new SellTickets2();
Thread thread1 = new Thread(sell, "1号窗口");
Thread thread2 = new Thread(sell, "2号窗口");
Thread thread3 = new Thread(sell, "3号窗口");
Thread thread4 = new Thread(sell, "4号窗口");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
/**
- 补充说明
- 由于Synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否。
- 而ReentrantLock是使用代码实现的,系统无法自动释放锁,所以需要在代码中的finally子句中显示释放锁loci.unlock();
- 另外,在并发量较小的情况下,使用Synchronized是个不错的选择;但是在并发量比较高的情况下,其性能会严重下降,
- 此时,使用ReentrantLock是不错的方案
- ====================================================================================
- 在使用Synchronized代码块时,可以与wait、notify、notifyAll一起使用,从而进一步实现线程的通信。
- 其中,wait方法会释放占有的对象锁,当前线程进入等待池,释放CPU,而其他正在等待的线程即可抢占此锁,
- 获得锁的线程即可运行程序,
- 线程sleep()方法则表示,当前线程会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁,也就是说
- 在休眠期间,其他线程依然无法进入被同步保护的代码内部,当前线程休眠结束时,会重新获得cpu的执行权,
- 从而执行被同步保护的代码
- wait()和sleep()最大的不同在于,wait()会释放对象锁,而sleep()不会释放对象锁。
- notify()方法会唤醒因为调用对象的wait()而处于等待状态的线程,从而使得该线程有机会获取对象锁。
- 调用notify()后,当前线程并不会立即释放锁,而是继续执行当前代码,直到Synchronized中代码执行
- 完毕后,才会释放对象锁。JVM会在等待的线程中调度一个线程去获取对象锁,执行代码。
- 需要注意的是,wait()和notify()必须在synchronized代码块中调用。
- notifyAll()是唤醒所有等待的进程。
*/