Thread-synchronized同步 -火车票实例

来源:互联网 发布:java native的用法 编辑:程序博客网 时间:2024/06/06 22:23

线程安全问题产生的原因:
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:20Thread-1:18Thread-1:17Thread-1:16Thread-1:15Thread-1:14Thread-1:13Thread-1:12Thread-1:11Thread-1:10Thread-1:9Thread-1:8Thread-1:7Thread-1:6Thread-1:5Thread-1:4Thread-1:3Thread-1:2Thread-1:1Thread-0:19Exception 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
原创粉丝点击