需求:某车站出售舟山至宁波的车票,共一百张,有三个窗口卖票,请设计一个程序模拟窗口卖票
分析:
1.定义一个SellTicket类实现Runnable接口,并重写run方法,并定义车票总张数
2.在run方法中判断票是否大于0;
是:卖票,并告知哪个窗口卖出的,卖票后总票数减一
否:提示没票了
3.定义一个测试类,创建SellTicket类对象,并作为参数创建三个Thread类对象,赋予线程名
4.启动线程
SellTicket类
public class SellTicket implements Runnable{
    //定义总张数
    private  int tickets=100;
    @Override
    public void run() {
        while (true) {
            //判断车票是否大于0
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张车票");
                tickets--;
            } 
       }
    }
}
SellTicketDemo类
public class SellTicketDemo {
    public static void main(String[] args) {
        //创建SellTicket类对象
        SellTicket st=new SellTicket();
        //作为参数创建三个Thread类对象,赋予线程名
        Thread t=new Thread(st,"窗口一");
        Thread t1=new Thread(st,"窗口二");
        Thread t2=new Thread(st,"窗口三");
        //启动线程
        t.start();
        t1.start();
        t2.start();
    }
}
经过运行发现会出现两个问题:
1.三个线程卖出了相同号码的车票
2.卖出了负数的车票
导致两个问题出现的原因是线程的随机性导致的数据安全问题。
一、那么如何判断多线程程序是否有数据安全问题?
1.判断程序是否是多线程环境
2.判断程序是否有共享数据
3.判断程序是否有多条语句操作共享数据
二、如何解决多线程安全问题?
1.基本思想:让程序没有安全问题的环境
2.把多条语句操作共享数据的代码块锁起来,让任意时刻只能有一个线程执行
这里使用同步代码块的方式来解决
三、同步代码块
格式:
synchronized(任意对象){
多条语句操作共享数据的代码;
}
synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看作是一把锁
修改后SellTicket类
import static java.lang.Thread.sleep;
public class SellTicket implements Runnable{
    //定义总张数
    private  int tickets=100;
    //定义一把锁
    private Object obj=new Object();
    @Override
    public void run() {
        synchronized (obj){
        while (true) {
            //判断车票是否大于0
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张车票");
                tickets--;
                //模仿出票
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
       }
    }
}
这样就解决了以上两个问题。
四、同步代码块的优缺点
1.优点:解决了多线程的数据安全问题
2.缺点:当线程很多时,因为每个线程都会去判断同步代码块中的锁,很耗费资源,会降低程序的运行效率
五、同步方法
1.同步方法就是把synchronized关键字加在方法上
格式:
修饰符synchronized 返回值类型 方法名(方法参数){}
public synchronized void sellTiket(){}
同步方法的锁对象是 this
synchronized (this)
2.同步静态方法就是把synchronized关键字加在静态方法上
格式:
修饰符 static synchronized 返回值类型 方法名(方法参数){}
public static synchronized void sellTiket(){}
同步方法的锁对象是类名.class
synchronized (SellTicket.class)
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号