线程安全问题

public class SaleTicket extends Thread {
    int num = 50;
    public SaleTicket(String name){
        super(name);
    }
    @Override
    public void run(){
        while(true){
            if(num>0){
                System.out.println (Thread.currentThread ().getName ()+"售出了第"+num+"张票");
                num--;
            }else {
                System.out.println ("卖完了。。");
                break;
            }
        }

    }

    public static void main(String[] args) {
        SaleTicket thread1 = new SaleTicket ("窗口1");
        SaleTicket thread2 = new SaleTicket ("窗口2");
        SaleTicket thread3 = new SaleTicket ("窗口3");
        thread1.start ();
        thread2.start ();
        thread3.start ();
    }
}
窗口3售出了第50张票
窗口3售出了第49张票
窗口3售出了第48张票
窗口3售出了第47张票
窗口3售出了第46张票
窗口3售出了第45张票
窗口3售出了第44张票
窗口3售出了第43张票
窗口3售出了第42张票
窗口3售出了第41张票
窗口3售出了第40张票
窗口3售出了第39张票
窗口3售出了第38张票
窗口3售出了第37张票
窗口3售出了第36张票
窗口3售出了第35张票
窗口3售出了第34张票
窗口1售出了第50张票
窗口2售出了第50张票
窗口2售出了第49张票
窗口1售出了第49张票
窗口3售出了第33张票
窗口1售出了第48张票
窗口1售出了第47张票
窗口1售出了第46张票
窗口1售出了第45张票
窗口1售出了第44张票
窗口1售出了第43张票
窗口1售出了第42张票
窗口1售出了第41张票
窗口1售出了第40张票
窗口1售出了第39张票
窗口1售出了第38张票
窗口1售出了第37张票
窗口1售出了第36张票
窗口1售出了第35张票
窗口1售出了第34张票
窗口1售出了第33张票
窗口1售出了第32张票
窗口1售出了第31张票
窗口1售出了第30张票
窗口1售出了第29张票
窗口1售出了第28张票
窗口1售出了第27张票
窗口1售出了第26张票
窗口1售出了第25张票
窗口1售出了第24张票
窗口1售出了第23张票
窗口1售出了第22张票
窗口1售出了第21张票
窗口1售出了第20张票
窗口1售出了第19张票
窗口1售出了第18张票
窗口1售出了第17张票
窗口1售出了第16张票
窗口1售出了第15张票
窗口1售出了第14张票
窗口1售出了第13张票
窗口1售出了第12张票
窗口1售出了第11张票
窗口1售出了第10张票
窗口1售出了第9张票
窗口1售出了第8张票
窗口1售出了第7张票
窗口1售出了第6张票
窗口1售出了第5张票
窗口1售出了第4张票
窗口1售出了第3张票
窗口1售出了第2张票
窗口1售出了第1张票
卖完了。。
窗口2售出了第48张票
窗口3售出了第32张票
窗口2售出了第47张票
窗口3售出了第31张票
窗口2售出了第46张票
窗口3售出了第30张票
窗口2售出了第45张票
窗口3售出了第29张票
窗口2售出了第44张票
窗口3售出了第28张票
窗口2售出了第43张票
窗口3售出了第27张票
窗口2售出了第42张票
窗口3售出了第26张票
窗口2售出了第41张票
窗口3售出了第25张票
窗口2售出了第40张票
窗口3售出了第24张票
窗口2售出了第39张票
窗口3售出了第23张票
窗口2售出了第38张票
窗口3售出了第22张票
窗口2售出了第37张票
窗口3售出了第21张票
窗口2售出了第36张票
窗口3售出了第20张票
窗口2售出了第35张票
窗口3售出了第19张票
窗口2售出了第34张票
窗口3售出了第18张票
窗口2售出了第33张票
窗口3售出了第17张票
窗口2售出了第32张票
窗口3售出了第16张票
窗口2售出了第31张票
窗口3售出了第15张票
窗口2售出了第30张票
窗口3售出了第14张票
窗口2售出了第29张票
窗口3售出了第13张票
窗口3售出了第12张票
窗口2售出了第28张票
窗口3售出了第11张票
窗口2售出了第27张票
窗口3售出了第10张票
窗口3售出了第9张票
窗口3售出了第8张票
窗口3售出了第7张票
窗口3售出了第6张票
窗口3售出了第5张票
窗口3售出了第4张票
窗口3售出了第3张票
窗口3售出了第2张票
窗口3售出了第1张票
卖完了。。
窗口2售出了第26张票
窗口2售出了第25张票
窗口2售出了第24张票
窗口2售出了第23张票
窗口2售出了第22张票
窗口2售出了第21张票
窗口2售出了第20张票
窗口2售出了第19张票
窗口2售出了第18张票
窗口2售出了第17张票
窗口2售出了第16张票
窗口2售出了第15张票
窗口2售出了第14张票
窗口2售出了第13张票
窗口2售出了第12张票
窗口2售出了第11张票
窗口2售出了第10张票
窗口2售出了第9张票
窗口2售出了第8张票
窗口2售出了第7张票
窗口2售出了第6张票
窗口2售出了第5张票
窗口2售出了第4张票
窗口2售出了第3张票
窗口2售出了第2张票
窗口2售出了第1张票
卖完了。。

Process finished with exit code 0

为什么50张票卖出去了150份?

num是非静态的成员变量,非静态成员变量数据在每个对象中都会维护一份数据

解决办法:把num变成static

package com.longteng.lesson2;

public class SaleTicket extends Thread {
    static  int num = 50;
    public SaleTicket(String name){
        super(name);
    }
    @Override
    public void run(){
        while(true){
            if(num>0){
                System.out.println (Thread.currentThread ().getName ()+"售出了第"+num+"张票");
                num--;
            }else {
                System.out.println ("卖完了。。");
                break;
            }
        }

    }

    public static void main(String[] args) {
        SaleTicket thread1 = new SaleTicket ("窗口1");
        SaleTicket thread2 = new SaleTicket ("窗口2");
        SaleTicket thread3 = new SaleTicket ("窗口3");
        thread1.start ();
        thread2.start ();
        thread3.start ();
    }
}
窗口3售出了第50张票
窗口3售出了第49张票
窗口3售出了第48张票
窗口3售出了第47张票
窗口3售出了第46张票
窗口3售出了第45张票
窗口3售出了第44张票
窗口3售出了第43张票
窗口3售出了第42张票
窗口3售出了第41张票
窗口3售出了第40张票
窗口3售出了第39张票
窗口3售出了第38张票
窗口3售出了第37张票
窗口3售出了第36张票
窗口3售出了第35张票
窗口3售出了第34张票
窗口3售出了第33张票
窗口3售出了第32张票
窗口3售出了第31张票
窗口3售出了第30张票
窗口3售出了第29张票
窗口3售出了第28张票
窗口3售出了第27张票
窗口3售出了第26张票
窗口3售出了第25张票
窗口3售出了第24张票
窗口3售出了第23张票
窗口3售出了第22张票
窗口3售出了第21张票
窗口3售出了第20张票
窗口3售出了第19张票
窗口3售出了第18张票
窗口3售出了第17张票
窗口3售出了第16张票
窗口3售出了第15张票
窗口3售出了第14张票
窗口3售出了第13张票
窗口3售出了第12张票
窗口3售出了第11张票
窗口3售出了第10张票
窗口3售出了第9张票
窗口3售出了第8张票
窗口3售出了第7张票
窗口3售出了第6张票
窗口3售出了第5张票
窗口3售出了第4张票
窗口3售出了第3张票
窗口3售出了第2张票
窗口3售出了第1张票
卖完了。。
窗口1售出了第50张票
卖完了。。
窗口2售出了第50张票
卖完了。。

Process finished with exit code 0

出现了线程安全

在什么情况下才可能出现线程安全问题

1、存在两个或者两个以上的线程对象,而且线程之间共享着一个资源

2、有多个语句操作了共享资源

如何解决线程安全问题?sun 提供了线程同步机制让我们解决这类问题

java线程同步机制的方式:

方式一:同步代码块

synchronized(锁对象){

需要被同步的代码

}

方式二:同步函数

同步代码块要注意的事项:

1、任意一个对象都可以作为锁对象。凡是对象内部都维护了一个状态,java同步机制就是使用了对象中的状态作为了锁的标识

2、在同步代码块中调用sleep方法并不会释放锁对象

3、只有真正存在线程安全问题的时候才使用同步代码块,否则会降低效率的

4、多线程操作的锁对象必须是唯一共享的,否则无效

package com.longteng.lesson2;

public class SaleTicket extends Thread {
    static Object o =new Object ();
    static  int num = 50;
    public SaleTicket(String name){
        super(name);
    }
    @Override
    public void run(){
        while(true){
            synchronized (o) {
                if (num > 0) {
                    System.out.println (Thread.currentThread ().getName () + "售出了第" + num + "张票");
                    num--;
                } else {
                    System.out.println ("卖完了。。");
                    break;
                }
            }
        }

    }

    public static void main(String[] args) {
        SaleTicket thread1 = new SaleTicket ("窗口1");
        SaleTicket thread2 = new SaleTicket ("窗口2");
        SaleTicket thread3 = new SaleTicket ("窗口3");
        thread1.start ();
        thread2.start ();
        thread3.start ();
    }
}
package com.longteng.lesson2;

public class SaleTicket extends Thread {
    static  int num = 50;
    public SaleTicket(String name){
        super(name);
    }
    @Override
    public void run(){
        while(true){
            synchronized ("锁对象") {
                if (num > 0) {
                    System.out.println (Thread.currentThread ().getName () + "售出了第" + num + "张票");
                    num--;
                } else {
                    System.out.println ("卖完了。。");
                    break;
                }
            }
        }

    }

    public static void main(String[] args) {
        SaleTicket thread1 = new SaleTicket ("窗口1");
        SaleTicket thread2 = new SaleTicket ("窗口2");
        SaleTicket thread3 = new SaleTicket ("窗口3");
        thread1.start ();
        thread2.start ();
        thread3.start ();
    }
}
窗口1售出了第50张票
窗口3售出了第49张票
窗口3售出了第48张票
窗口3售出了第47张票
窗口3售出了第46张票
窗口3售出了第45张票
窗口3售出了第44张票
窗口3售出了第43张票
窗口3售出了第42张票
窗口3售出了第41张票
窗口3售出了第40张票
窗口1售出了第39张票
窗口1售出了第38张票
窗口1售出了第37张票
窗口1售出了第36张票
窗口1售出了第35张票
窗口1售出了第34张票
窗口1售出了第33张票
窗口1售出了第32张票
窗口1售出了第31张票
窗口1售出了第30张票
窗口1售出了第29张票
窗口1售出了第28张票
窗口1售出了第27张票
窗口1售出了第26张票
窗口1售出了第25张票
窗口1售出了第24张票
窗口1售出了第23张票
窗口1售出了第22张票
窗口1售出了第21张票
窗口1售出了第20张票
窗口1售出了第19张票
窗口1售出了第18张票
窗口1售出了第17张票
窗口1售出了第16张票
窗口1售出了第15张票
窗口1售出了第14张票
窗口1售出了第13张票
窗口1售出了第12张票
窗口1售出了第11张票
窗口1售出了第10张票
窗口1售出了第9张票
窗口1售出了第8张票
窗口1售出了第7张票
窗口1售出了第6张票
窗口1售出了第5张票
窗口1售出了第4张票
窗口1售出了第3张票
窗口1售出了第2张票
窗口1售出了第1张票
卖完了。。
卖完了。。
卖完了。。

Process finished with exit code 0

多线程操作的锁对象必须是唯一共享的,否则无效

package com.longteng.lesson2;

public class SaleTicket extends Thread {
    static  int num = 50;
    public SaleTicket(String name){
        super(name);
    }
    @Override
    public void run(){
        while(true){
            synchronized (new Object ()) {//锁是个变量
                if (num > 0) {
                    System.out.println (Thread.currentThread ().getName () + "售出了第" + num + "张票");
                    num--;
                } else {
                    System.out.println ("卖完了。。");
                    break;
                }
            }
        }

    }

    public static void main(String[] args) {
        SaleTicket thread1 = new SaleTicket ("窗口1");
        SaleTicket thread2 = new SaleTicket ("窗口2");
        SaleTicket thread3 = new SaleTicket ("窗口3");
        thread1.start ();
        thread2.start ();
        thread3.start ();
    }
}
窗口1售出了第50张票
窗口1售出了第49张票
窗口1售出了第48张票
窗口1售出了第47张票
窗口1售出了第46张票
窗口1售出了第45张票
窗口1售出了第44张票
窗口1售出了第43张票
窗口1售出了第42张票
窗口1售出了第41张票
窗口1售出了第40张票
窗口1售出了第39张票
窗口1售出了第38张票
窗口1售出了第37张票
窗口1售出了第36张票
窗口1售出了第35张票
窗口1售出了第34张票
窗口1售出了第33张票
窗口1售出了第32张票
窗口1售出了第31张票
窗口3售出了第50张票
窗口3售出了第29张票
窗口3售出了第28张票
窗口3售出了第27张票
窗口3售出了第26张票
窗口3售出了第25张票
窗口3售出了第24张票
窗口3售出了第23张票
窗口3售出了第22张票
窗口3售出了第21张票
窗口3售出了第20张票
窗口3售出了第19张票
窗口3售出了第18张票
窗口3售出了第17张票
窗口3售出了第16张票
窗口3售出了第15张票
窗口3售出了第14张票
窗口3售出了第13张票
窗口3售出了第12张票
窗口3售出了第11张票
窗口3售出了第10张票
窗口3售出了第9张票
窗口3售出了第8张票
窗口3售出了第7张票
窗口3售出了第6张票
窗口3售出了第5张票
窗口3售出了第4张票
窗口3售出了第3张票
窗口3售出了第2张票
窗口3售出了第1张票
卖完了。。
卖完了。。
窗口1售出了第30张票
卖完了。。

Process finished with exit code 0

  

原文地址:https://www.cnblogs.com/zhou-test/p/9867813.html