多线程>>>多线程的同步机制
多线程>>>多线程的同步机制
栗子:
卖票:
创建个窗口卖票,总票数为100张.使用实现Runnable接口的方式👇
public class TestThread2 {
public static void main(String[] args) {
//实例化卖票线程的实现类
Ticket ticket = new Ticket();
//新建添加卖票线程的实现类的线程,让两个线程去同时卖票
Thread thread1 = new Thread(ticket);
Thread thread2 = new Thread(ticket);
//调用start方法完成创建,##调用start方法会自动调用重写的run方法
thread1.start();
thread2.start();
}
}
//卖票线程的实现类
class Ticket implements Runnable {
private int tickets = 100;
@Override
public void run() {
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "张票");
tickets--;
}
}
}
}
输出的结果👇
Thread-0正在卖第100张票
Thread-0正在卖第99张票
Thread-0正在卖第98张票
Thread-0正在卖第97张票
Thread-0正在卖第96张票
Thread-0正在卖第95张票
Thread-0正在卖第94张票
Thread-0正在卖第93张票
Thread-0正在卖第92张票
Thread-0正在卖第91张票
Thread-0正在卖第90张票
Thread-0正在卖第89张票
Thread-0正在卖第88张票
Thread-0正在卖第87张票
Thread-0正在卖第86张票
Thread-0正在卖第85张票
Thread-0正在卖第84张票
Thread-0正在卖第83张票
Thread-0正在卖第82张票
Thread-0正在卖第81张票
Thread-0正在卖第80张票
Thread-0正在卖第79张票
Thread-0正在卖第78张票
Thread-0正在卖第77张票
Thread-0正在卖第76张票
Thread-0正在卖第75张票
Thread-0正在卖第74张票
Thread-0正在卖第73张票
Thread-0正在卖第72张票
Thread-0正在卖第71张票
Thread-0正在卖第70张票
Thread-0正在卖第69张票
Thread-0正在卖第68张票
Thread-0正在卖第67张票
Thread-0正在卖第66张票
Thread-0正在卖第65张票
Thread-0正在卖第64张票
Thread-0正在卖第63张票
Thread-0正在卖第62张票
Thread-0正在卖第61张票
Thread-0正在卖第60张票
Thread-0正在卖第59张票
Thread-0正在卖第58张票
Thread-0正在卖第57张票
Thread-0正在卖第56张票
Thread-0正在卖第55张票
Thread-0正在卖第54张票
Thread-0正在卖第53张票
Thread-0正在卖第52张票
Thread-0正在卖第51张票
Thread-0正在卖第50张票
Thread-0正在卖第49张票
Thread-0正在卖第48张票
Thread-0正在卖第47张票
Thread-0正在卖第46张票
Thread-0正在卖第45张票
Thread-0正在卖第44张票
Thread-0正在卖第43张票
Thread-0正在卖第42张票
Thread-0正在卖第41张票
Thread-0正在卖第40张票
Thread-0正在卖第39张票
Thread-0正在卖第38张票
Thread-0正在卖第37张票
Thread-0正在卖第36张票
Thread-0正在卖第35张票
Thread-0正在卖第34张票
Thread-0正在卖第33张票
Thread-0正在卖第32张票
Thread-0正在卖第31张票
Thread-0正在卖第30张票
Thread-0正在卖第29张票
Thread-0正在卖第28张票
Thread-0正在卖第27张票
Thread-0正在卖第26张票
Thread-0正在卖第25张票
Thread-0正在卖第24张票
Thread-0正在卖第23张票
Thread-0正在卖第22张票
Thread-0正在卖第21张票
Thread-0正在卖第20张票
Thread-0正在卖第19张票
Thread-0正在卖第18张票
Thread-0正在卖第17张票
Thread-0正在卖第16张票
Thread-0正在卖第15张票
Thread-0正在卖第14张票
Thread-0正在卖第13张票
Thread-0正在卖第12张票
Thread-0正在卖第11张票
Thread-0正在卖第10张票
Thread-0正在卖第9张票
Thread-0正在卖第8张票
Thread-0正在卖第7张票
Thread-0正在卖第6张票
Thread-0正在卖第5张票
Thread-0正在卖第4张票
Thread-0正在卖第3张票
Thread-0正在卖第2张票
Thread-0正在卖第1张票
Thread-1正在卖第100张票 ##Thread-1在重复卖票,这显然不是我们想要的
Process finished with exit code -1
- 1.问题:卖票过程中,出现了重票、错票 -->出现了线程的安全问题
- 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。
- 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。
Java解决方案:同步机制
在Java中,我们通过同步机制,来解决线程的安全问题。
方式一:同步代码块
* synchronized(同步监视器){
* //需要被同步的代码
*
* }
这样👇
//卖票线程的实现类
class Ticket implements Runnable {
private int tickets = 100;
Object object = new Object();
//这里的Object是同步监视器
@Override
public void run() {
while (true) {
synchronized (object) {
//这里的synchronized应该放在循环里面
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "张票");
tickets--;
}
}
}
}
}
看问题解决了👇
Thread-0正在卖第100张票
Thread-1正在卖第99张票
Thread-1正在卖第98张票
Thread-1正在卖第97张票
Thread-1正在卖第96张票
Thread-1正在卖第95张票
Thread-1正在卖第94张票
Thread-1正在卖第93张票
Thread-1正在卖第92张票
Thread-1正在卖第91张票
Thread-1正在卖第90张票
Thread-1正在卖第89张票
Thread-1正在卖第88张票
Thread-1正在卖第87张票
Thread-1正在卖第86张票
Thread-1正在卖第85张票
Thread-1正在卖第84张票
Thread-1正在卖第83张票
Thread-1正在卖第82张票
Thread-1正在卖第81张票
Thread-1正在卖第80张票
Thread-1正在卖第79张票
Thread-1正在卖第78张票
Thread-1正在卖第77张票
Thread-1正在卖第76张票
Thread-1正在卖第75张票
Thread-1正在卖第74张票
Thread-1正在卖第73张票
Thread-1正在卖第72张票
Thread-1正在卖第71张票
Thread-1正在卖第70张票
Thread-1正在卖第69张票
Thread-1正在卖第68张票
Thread-1正在卖第67张票
Thread-1正在卖第66张票
Thread-1正在卖第65张票
Thread-1正在卖第64张票
Thread-1正在卖第63张票
Thread-1正在卖第62张票
Thread-1正在卖第61张票
Thread-1正在卖第60张票
Thread-1正在卖第59张票
Thread-1正在卖第58张票
Thread-1正在卖第57张票
Thread-1正在卖第56张票
Thread-1正在卖第55张票
Thread-1正在卖第54张票
Thread-1正在卖第53张票
Thread-1正在卖第52张票
Thread-1正在卖第51张票
Thread-1正在卖第50张票
Thread-1正在卖第49张票
Thread-1正在卖第48张票
Thread-1正在卖第47张票
Thread-1正在卖第46张票
Thread-1正在卖第45张票
Thread-1正在卖第44张票
Thread-1正在卖第43张票
Thread-1正在卖第42张票
Thread-1正在卖第41张票
Thread-1正在卖第40张票
Thread-1正在卖第39张票
Thread-1正在卖第38张票
Thread-1正在卖第37张票
Thread-1正在卖第36张票
Thread-1正在卖第35张票
Thread-1正在卖第34张票
Thread-1正在卖第33张票
Thread-1正在卖第32张票
Thread-1正在卖第31张票
Thread-1正在卖第30张票
Thread-1正在卖第29张票
Thread-1正在卖第28张票
Thread-1正在卖第27张票
Thread-1正在卖第26张票
Thread-1正在卖第25张票
Thread-1正在卖第24张票
Thread-1正在卖第23张票
Thread-1正在卖第22张票
Thread-1正在卖第21张票
Thread-1正在卖第20张票
Thread-1正在卖第19张票
Thread-1正在卖第18张票
Thread-1正在卖第17张票
Thread-1正在卖第16张票
Thread-1正在卖第15张票
Thread-1正在卖第14张票
Thread-1正在卖第13张票
Thread-1正在卖第12张票
Thread-1正在卖第11张票
Thread-1正在卖第10张票
Thread-1正在卖第9张票
Thread-1正在卖第8张票
Thread-1正在卖第7张票
Thread-1正在卖第6张票
Thread-1正在卖第5张票
Thread-1正在卖第4张票
Thread-1正在卖第3张票
Thread-1正在卖第2张票
Thread-1正在卖第1张票
Process finished with exit code -1
说明:
操作共享数据的代码,即为需要被同步的代码。 -->不能包含代码多了,也不能包含代码少了。
共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。
同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。
要求:多个线程必须要共用同一把锁。
补充:
- 在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。
- 在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。
方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
关于同步方法的总结:
同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
非静态的同步方法,同步监视器是:this
静态的同步方法,同步监视器是:当前类本身
方式三:Lock锁 --- JDK5.0新增
面试题:synchronized 与 Lock的异同?
相同:二者都可以解决线程安全问题
不同:
- synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
Lock需要手动的启动同步(lock(),同时结束同步也需要手动的实现(unlock())
利弊
同步的方式
- 好处是 解决了线程的安全问题。
- 操作同步代码时,只能一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。

浙公网安备 33010602011771号