如何保证线程安全

1、同步代码块。

synchronized(共享资源对象){//对共享资源对象加锁
//代码(原子操作) 
}

注:
每个对象都有一个互斥锁标记,用来分配给线程的。
只有拥有对象互斥锁标记的线程,才可以进入该对象加锁的同步代码块。
线程退出同步代码块时,会释放相应的互斥锁标记。

 

代码示例:

//当前数组下标值
    private static int INDEX = 0;

    public static void main(String[] args) throws InterruptedException {
        //定义一个长度为5的数组
        String[] arr = new String[5];
        //定义两个线程,分别往数组中插入不同的值。
        //这里我们期望可以得到["ONE","TWO",null.null,null]
        Thread t1 = new Thread(() -> {
            synchronized (arr) {
                arr[INDEX] = "ONE";
                INDEX++;
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (arr) {
                arr[INDEX] = "TWO";
                INDEX++;
            }
        });
        //启动线程
        t1.start();
        t2.start();
        //这里为了保证输出时这两个线程已经执行完毕,使用join方法来阻塞主线程
        t1.join();
        t2.join();

        //打印数据数据
        System.out.println(Arrays.toString(arr));
    }

这时的结果无论执行多少次都不会出现元素覆盖的情况,结果为[ONE, TWO, null, null, null]或[TWO, ONE, null, null, null]。因为没有去控制线程执行顺序。

 

 

2、同步方法。

synchronized 返回值类型 方法名称(形参列表){//对当前对象this加锁
//代码(原子操作)
}

注:
只有拥有该对象互斥锁标记的线程才能进入该对象加锁的同步方法中。
线程退出同步方法时,会释放拥有的互斥锁标记。

 

代码示例:

//假设有三个售票窗口,总共销售100张票
    private static int TICKET = 100;

    public static void main(String[] args) {
        //定义售票窗口,执行售票方法
        Thread t1 = new Thread(() -> {
            while (true) {
                if (!sale()) {
                    break;
                }
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            while (true) {
                if (!sale()) {
                    break;
                }
            }
        }, "t2");
        Thread t3 = new Thread(() -> {
            while (true) {
                if (!sale()) {
                    break;
                }
            }
        }, "t3");
        //启动三个线程,开始卖票
        t1.start();
        t2.start();
        t3.start();

    }

    /**
     * 静态方法,锁的是当前方法所在的类
     * 非静态方法,锁的是this,调用该方法的对象。
     * @return
     */
    private synchronized static boolean sale() {
        if (TICKET <= 0) {
            return false;
        }
        System.out.println(Thread.currentThread().getName() + "销售了第" + TICKET + "张票");
        TICKET--;
        return true;
    }

输出结果:

t1销售了第100张票
t1销售了第99张票
t1销售了第98张票
t1销售了第97张票
t1销售了第96张票
t1销售了第95张票
t1销售了第94张票
t1销售了第93张票
t2销售了第92张票
t2销售了第91张票
t2销售了第90张票
t2销售了第89张票
t2销售了第88张票
t2销售了第87张票
t2销售了第86张票
t2销售了第85张票
t2销售了第84张票
t2销售了第83张票
t2销售了第82张票
t2销售了第81张票
t2销售了第80张票
t2销售了第79张票
t2销售了第78张票
t2销售了第77张票
t2销售了第76张票
t2销售了第75张票
t2销售了第74张票
t2销售了第73张票
t2销售了第72张票
t2销售了第71张票
t2销售了第70张票
t2销售了第69张票
t2销售了第68张票
t2销售了第67张票
t2销售了第66张票
t2销售了第65张票
t2销售了第64张票
t2销售了第63张票
t2销售了第62张票
t2销售了第61张票
t2销售了第60张票
t2销售了第59张票
t2销售了第58张票
t2销售了第57张票
t2销售了第56张票
t2销售了第55张票
t2销售了第54张票
t2销售了第53张票
t2销售了第52张票
t2销售了第51张票
t2销售了第50张票
t2销售了第49张票
t2销售了第48张票
t2销售了第47张票
t2销售了第46张票
t2销售了第45张票
t2销售了第44张票
t2销售了第43张票
t2销售了第42张票
t2销售了第41张票
t2销售了第40张票
t2销售了第39张票
t2销售了第38张票
t2销售了第37张票
t2销售了第36张票
t2销售了第35张票
t2销售了第34张票
t2销售了第33张票
t2销售了第32张票
t2销售了第31张票
t2销售了第30张票
t2销售了第29张票
t2销售了第28张票
t2销售了第27张票
t2销售了第26张票
t2销售了第25张票
t2销售了第24张票
t2销售了第23张票
t2销售了第22张票
t2销售了第21张票
t2销售了第20张票
t2销售了第19张票
t2销售了第18张票
t2销售了第17张票
t2销售了第16张票
t2销售了第15张票
t2销售了第14张票
t2销售了第13张票
t2销售了第12张票
t2销售了第11张票
t2销售了第10张票
t2销售了第9张票
t2销售了第8张票
t2销售了第7张票
t2销售了第6张票
t2销售了第5张票
t2销售了第4张票
t2销售了第3张票
t2销售了第2张票
t3销售了第1张票

Process finished with exit code 0

 

posted @ 2022-12-27 03:05  Amireux-126  阅读(168)  评论(0)    收藏  举报