Thread-synchronized同步 -火车票实例

线程安全问题产生的原因:
1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算。就会导致线程安全问题的产生。

解决思路;
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程时不可以参与运算的。
必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中,用同步代码块就可以解决这个问题。

同步代码块的格式:

synchronized(对象)
{
需要被同步的代码 ;
}

同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁。

例1:多个窗口购买火车票实例:

package day04;

public class JavaTest {

    public static void main(String[] args) {
        SaleTicket st=new SaleTicket();
        Thread t1=new Thread(st,"一号窗口");
        Thread t2=new Thread(st,"二号窗口");
        Thread t3=new Thread(st,"三号窗口");
        Thread t4=new Thread(st,"四号窗口");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class SaleTicket implements Runnable{//sale英 [seɪl]  n.拍卖;卖,出卖;
    private int tickets=100;
    @Override
    public void run() {
        while(tickets>0){
            sale();
        }
    }
    private synchronized void sale(){//synchronized 同步。
        if(tickets>0){
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(100-tickets+1)+"张票");
            tickets --;
            try{
                Thread.sleep(500);//假设购票过程需要500毫秒。
            }catch(InterruptedException e){
                e.printStackTrace();
            }

        }
    }
}

运行结果:

一号窗口卖出了第1张票
四号窗口卖出了第2张票
二号窗口卖出了第3张票
三号窗口卖出了第4张票
三号窗口卖出了第5张票
.................
四号窗口卖出了第99张票
四号窗口卖出了第100张票

例2: 创建两个线程t1和t2同时减桌子上的20颗豆子。至到豆子的数量减为0,人为抛出异常为止。这是桌上的豆子就是公共事件,两个线程会同时去访问。所以要加synchronized将公共资源同步的锁起来。

package day04;
/**
 * 当多个线程同时操作一段数据时,由于线程切换的不确定性,可能会导致逻辑出现混乱。
 * @author Administrator
 */
public class SyncDemo {
    public static void main(String[] args) {
        final Table table = new Table();
        Thread t1 = new Thread(){
            public void run(){
                while(true){
                    int bean = table.getBean();
                    //模拟CPU没有时间了
                    Thread.yield();     //yield英 [ji:ld] vi.放弃;退让,退位
                    System.out.println(getName()+":"+bean);
                }
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                while(true){
                    int bean = table.getBean();
                    Thread.yield();  //yield英 [ji:ld] vi.放弃;退让,退位
                    System.out.println(getName()+":"+bean);
                }
            }
        };
        t1.start();
        t2.start();
    }
}

class Table{
    private int beans = 20;//桌子上有20个豆子
    /*
     * 当一个方法被synchronized修饰后,该方法 就是一个同步方法了。多个线程调用时不会同时进到方法内部。
     * 需要注意的是synchronized一定会给一个对象上锁。在这里,锁的是当前方法所属的对象。
     * 也就是上面main方法中创建的table实例。由于两个线程调用的是同一个table的getBean方法。所以两个线程不能同时进到方法内部。
     */
    public synchronized int getBean(){
        if(beans==0){throw new RuntimeException("没有豆子了!");}
        Thread.yield();
        return beans--;
    }
}

运行结果:

Thread-1:20
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
Thread-0:19
Exception in thread "Thread-1" Exception in thread "Thread-0" java.lang.RuntimeException: 没有豆子了!
    at day04.Table.getBean(SyncDemo.java:41)
    at day04.SyncDemo$2.run(SyncDemo.java:22)
java.lang.RuntimeException: 没有豆子了!
    at day04.Table.getBean(SyncDemo.java:41)
    at day04.SyncDemo$1.run(SyncDemo.java:12)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值