引入:书写一个卖票小程序的代码
//卖票逻辑书写阶段
//使用继承Thread的方法
public class Sellingtickets extends Thread{
static int ticket=100;
@Override
/*
* 卖票逻辑:三个窗口卖票,也就是说,只要三个窗口有票,就需要不停的使用循环来进行卖票操作
* 工作过程,使用各自线程在循环体里开始卖票,cup随机分配在哪个窗口买票,所以卖票的票号会
* 显示在不同的线程当中*/
public void run() {
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"票号为"+ticket);
ticket--;
}
else{
break;//跳出此次循环
}
}
}
}
//main函数书写阶段
public class Test {
public static void main(String args[]){
Sellingtickets Thread1=new Sellingtickets();//创建线程1
Sellingtickets Thread2=new Sellingtickets();//创建线程2
Sellingtickets Thread3=new Sellingtickets();//创建线程3
Thread1.start();
Thread2.start();
Thread3.start();
}
}
运行结果
得到重票
得到错票
思考:
1.为什么会造成这种情况
2.造成这种情况,该如何去解决
1.
因为在代码中,可能上一个线程正在执行语句,但是他还没有实现 ticket--的语句,其他的线程进来了,就会导致现在这个线程的票号,和上一个线程的票号一样,这就是线程的安全问题。
2.
解决:
使用同步代码块
语法:
synchornized(同步监视器){共享数据
}
同步监视器:简称锁,作用在于当有线程正在操作数据时,不让其他线程进来
注意点:同步监视器必须三个线程共用一个。
共享数据:可能会被多个线程同时执行的数据
简单逻辑:将不允许几个线程执行的程序用大括号包起来,锁上门,只有当这里面的程序执行好之后,才可以把门打开,让其他线程进来。
//代码实例
public class Sellingtickets extends Thread{
static int ticket=100;
static Lock A=new Lock();//造一把锁
@Override
/*
* 卖票逻辑:三个窗口卖票,也就是说,只要三个窗口有票,就需要不停的使用循环来进行卖票操作
* 工作过程,使用各自线程在循环体里开始卖票,cup随机分配在哪个窗口买票,所以卖票的票号会
* 显示在不同的线程当中*/
public void run() {
while(true){
synchronized (A){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"票号为"+ticket);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
}
else{
break;//跳出此次循环
}
}
}
}
}
运行结果(图未截完)
总结:
本节重点
1.卖票程序的逻辑书写
2.synchronized关键词的作用及使用---
作用:用来解决线程的不安全问题
使用
synchornized(同步监视器){
共享数据
}
3.同步监视器的注意点---同步监视器必须是所有线程共用一个
4.共享数据的范围---重点,别包错了,如果范围找错了,那么程序的逻辑会出错