1. 线程的同步
- 在这个案例中,出现了售票“超卖”的现象。
javascript:void(0) - 下面就使用
synchronized
解决售票“超卖”的问题
2. 线程同步机制
- 在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。
- 也可以这样理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。
3. 同步具体方法–Synchronized
- 同步代码块
synchronized(对象){ //得到对象的锁,才能操作同步代码
//需要被同步代码;
}
-
synchronized
还可以放在方法声明中,表示整个方法为同步方法
public synchronized void m (String name) {
//需要被同步的代码
}
- 如何理解:
就好像某小伙伴上厕所前先把门关上(上锁),完事后再出来(解锁),那么其它小伙伴就可在使用厕所了,如图: - 使用
synchronized
解决售票问题
- 假如票总数为10张,分别放在三个窗口上售卖
public class SellTicket {
public static void main(String[] args) {
SellTicket01 sellTicket01 = new SellTicket01();
SellTicket01 sellTicket02 = new SellTicket01();
SellTicket01 sellTicket03 = new SellTicket01();
sellTicket01.start();
sellTicket02.start();
sellTicket03.start();
}
}
//使用继承 Thread 方式,使用 synchronized 实现线程同步
class SellTicket01 extends Thread {
private static int ticketNum = 10; //让多个线程共享 ticketNum
private boolean loop = true; //控制run方法变量
public synchronized void sell() { //同步方法,在同一时刻,只能有一个线程来执行 sell 方法
if (ticketNum <= 0) {
System.out.println("售票结束...");
loop = false;
return;
}
//休眠50毫秒,模拟休息时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数" + (--ticketNum));
}
@Override
public synchronized void run() {
while (loop) {
sell(); // sell 方法是一个同步方法
}
}
}
- 因为有三个线程,所以都打印出结束语
- 使用
synchronized
同步,可以防止多个线程去操作同一段代码,造成售票“超卖”现象
4. 分析同步原理
5. 互斥锁
5.1 基本介绍
- 上面的锁也称:互斥锁
- Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
- 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任意时刻,只能有一个线程访问该对象。
- 关键字
synchronized
来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。 - 同步的局限性:导致程序的执行效率降低
- 同步方法(非静态的)的锁可以是
this
,也可以是其他对象(要求是同一个对象) - 同步方法(静态的)的锁为当前类本身。