天天看点

重学Java之线程同步1.线程不安全2.线程同步

线程同步主要是为了防止多线程情况下,资源访问冲突。

举个栗子,卖票,还有 2 张票,A B 两个线程同时操作,A 线程把剩余的2张票都卖了,此时 B 线程已经执行完判断是否有票的逻辑,B 也卖了 2 张票。这显然是不对的。

多线程情况下,在对数据操作时要确保线程安全。

于是有了线程同步机制,用来解决资源共享问题。

线程同步机制 就是在给定范围内给资源加上一把锁,只允许一个线程访问资源。

1.线程不安全

以卖票(奶茶)为例,总数固定,每次减1 ,3个线程同时操作,

public class TestSynchronized {

    public static void main(String[] args) {

        BuyRunnable runnable = new BuyRunnable();

        Thread thread1 = new Thread(runnable, "thread1");
        Thread thread2 = new Thread(runnable, "thread2");
        Thread thread3 = new Thread(runnable, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class BuyRunnable implements Runnable{

    private int milkTeeSum = 10;

    @Override
    public void run() {
        while (true) {
            if (milkTeeSum > 0) {
                try {
                    Thread.sleep(1000);//延时模拟卖奶茶
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("milkTee remain " + --milkTeeSum);
            }
        }
    }
}
           

运行结果

milkTee remain 9
milkTee remain 8
milkTee remain 7
milkTee remain 6
milkTee remain 5
milkTee remain 4
milkTee remain 3
milkTee remain 2
milkTee remain 1
milkTee remain 0
milkTee remain -1
milkTee remain -2
           

出现负数,这是不对的。

2.线程同步

使用

synchronized

关键字来加锁,

public class TestSynchronized {

    public static void main(String[] args) {

        BuyRunnable runnable = new BuyRunnable();

        Thread thread1 = new Thread(runnable, "thread1");
        Thread thread2 = new Thread(runnable, "thread2");
        Thread thread3 = new Thread(runnable, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class BuyRunnable implements Runnable{

    private int milkTeeSum = 10;

    @Override
    public void run() {
        while (true) {
            synchronized (this){
                if (milkTeeSum > 0) {
                    try {
                        Thread.sleep(1000);//延时模拟卖奶茶
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("milkTee remain " + --milkTeeSum);
                }
            }
        }
    }
}
           

运行结果,符合要求。

milkTee remain 9
milkTee remain 8
milkTee remain 7
milkTee remain 6
milkTee remain 5
milkTee remain 4
milkTee remain 3
milkTee remain 2
milkTee remain 1
milkTee remain 0
           

这是 同步块 。

还可以 同步方法,

public class TestSynchronized {

    public static void main(String[] args) {

        BuyRunnable runnable = new BuyRunnable();

        Thread thread1 = new Thread(runnable, "thread1");
        Thread thread2 = new Thread(runnable, "thread2");
        Thread thread3 = new Thread(runnable, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class BuyRunnable implements Runnable{

    private int milkTeeSum = 10;

    @Override
    public void run() {
        while (true) {
            soldMilkTee();
        }
    }

    private synchronized void soldMilkTee(){
        if (milkTeeSum > 0) {
            try{
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("milkTee remain " + --milkTeeSum);
        }
    }
}
           

本例效果,和同步块是一样的。