• 线程安全


    public class TicketetsRunable implements Runnable {
    private int tickets = 100; @Override public void run() { while (true) { //当tickets=1时 //有t1,t2,t3,t4线程过来抢夺访问权限 if (ticks > 0) { //t1进来了,因为使其睡眠一会(10毫秒),并没有立刻去执行tickets--操作,导致其他线程乘机而入
    //t2也进来了,同理。。 //t3.. //t4..

    //t1线程睡醒了,输出1,执行了 tickets-- 操作 //t2线程睡醒了,输出0,执行了.. //t3线程睡醒了,输出-1,执行了.. //t4线程睡醒了,输出-2,执行了.. try { Thread.sleep(10); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); } } } }
    /**
     *测试类
     */
    public class Test {
        public static void main(String[] args) {
            TicksRunable t = new TicksRunable();
            Thread t1 = new Thread(t, "售票员1");
            Thread t2 = new Thread(t, "售票员2");
            Thread t3 = new Thread(t, "售票员3");
            Thread t4 = new Thread(t, "售票员4");
            t1.start();
            t2.start();
            t3.start();
            t4.start();
    
        }
    }

    以上代码用4个线程模拟了售票,输出结果有时会出现0,-1,-2的票

       导致这种问题出现的原因:

           1.线程的随机性(如果几个线程按顺序执行的话就不会有问题,但是线程是随机性的,几个线程之间互相抢夺cpu的资源)

           2. 多个线程访问出现延迟 (如果线程抢到了访问权限,没有使其睡眠,进来就执行了,也没什么问题。但是如果线程发生延迟,就会出现问题)

       这就是线程安全问题,如何判断程序有没有线程安全问题:

            1.程序有共享数据

            2.多条语句操作共享数据

            3.多个线程访问

            解决线程安全问题,应从这三个方面入手。

      要解决上述示例代码的线程安全问题,可以把多条操作共享数据的代码作为一个整体看待,采用线程锁(线程同步)

    public class TicketsRunable implements Runnable {
    
        private int tickets = 100;
    
        private Object object = new Object();
    
        @Override
        public void run() {
            while (true) {
                // 当ticks=1
                // 有t1,t2,t3,t4线程过来抢夺方法执行权限
                // t1抢到了,它要进去,它看见没锁,它就进去了,进去之后就给锁上了
                // t2抢到了,它要进去,它看见门锁了,它就进不去了,只能等。
                // 等到t1出来了,去掉锁
                // t2看见没锁,它就进去了...
                synchronized (object) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(10);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()
                                + "正在出售第" + (tickets--) + "张票");
                    }
                }
    
            }
        }
    
    }

    以上代码使用同步技术让线程排队执行(操作共享数据的代码),避免了线程安全问题。和上厕所差不多,第一个人进去之后锁上门,第二个人想进去只有等到第一个人先出来

    同步代码块的语法是

    synchronized(对象){
    //同步的代码
    }

    ps:同步方法的锁对象是this

          同步静态方法的锁对象是当前类的字节码文件对象(Class)

            

         

  • 相关阅读:
    datagrid
    SQL语句
    JavaScript事件
    DOM和BOM
    JavaScript基础知识
    css
    网络编程常识
    集合框架
    多线程常识
    面向对象常识
  • 原文地址:https://www.cnblogs.com/sflik/p/4824078.html
Copyright © 2020-2023  润新知