Java多线程(四)synchronized 同步方法和同步块

Java为了解决多线程带来的安全问题,采用了同步的方式来解决安全问题。

解决多线程的安全问题,Java提供了三种方式:

同步方法

同步块

java juc包(锁机制)

线程不安全的产生,多个线程同时使用同一个资源,就会来带线程不安全问题。

例如:

public class Cinema {

    public static void main(String[] args) {
        TicketOffice office = new TicketOffice();
        //创建3个售票员
        Thread seller1 = new Thread(office);
        Thread seller2 = new Thread(office);
        Thread seller3 = new Thread(office);
        seller1.start();
        seller2.start();
        seller3.start();
     }
}

class TicketOffice implements Runnable {
    //定义10张电影票
    int ticket = 10;

    @Override
    public void run() {
        while (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //开始卖电影票,每售出一张电影票,就自动减去1
            System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticket--) + "张票!");
        }
    }
}

结果:

出现了重复售票(一票多卖,一女多嫁)和票数为负数的情况。

加Thread.sleep()只是为了让出错的概率增大

Thread-0正在卖第10张票!
Thread-1正在卖第10张票!
Thread-2正在卖第10张票!
Thread-1正在卖第9张票!
Thread-2正在卖第9张票!
Thread-0正在卖第9张票!
Thread-1正在卖第8张票!
Thread-2正在卖第7张票!
Thread-0正在卖第8张票!
Thread-0正在卖第6张票!
Thread-1正在卖第4张票!
Thread-2正在卖第5张票!
Thread-0正在卖第3张票!
Thread-2正在卖第2张票!
Thread-1正在卖第3张票!
Thread-1正在卖第1张票!
Thread-2正在卖第-1张票!
Thread-0正在卖第0张票!

同步代码块

下面是同步代码块的语法

synchronized(obj){
    //需要同步的地方
    //obj可以是任意共享的资源(对象),同步代码块同步的是对象
}

下面通过同步代码块来解决卖票问题

public class Cinema {


    public static void main(String[] args) {
        TicketOffice office = new TicketOffice();
        //创建3个售票员
        Thread seller1 = new Thread(office);
        Thread seller2 = new Thread(office);
        Thread seller3 = new Thread(office);
        seller1.start();
        seller2.start();
        seller3.start();
    }
}

class TicketOffice implements Runnable {
    //定义10张电影票
    int ticket = 10;
    Object obj = new Object();//这个一定要写在类里,不要写在方法里

    //写在类里面才是共享的资源,写在方法里面,每个线程都有自己的资源,就不是共享的了
    @Override
    public void run() {
        synchronized (obj) {
            while (ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //开始卖电影票,没售出一张电影票,就自动减去1
                System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticket--) + "张票!");
            }
        }
    }
}

同步方法

修饰符 synchronized 返回值 方法名(){
    //方法体
}

通过同步方法来解决线程安全问题

public class Cinema {


    public static void main(String[] args) {
        TicketOffice office = new TicketOffice();
        //创建3个售票员
        Thread seller1 = new Thread(office);
        Thread seller2 = new Thread(office);
        Thread seller3 = new Thread(office);
        seller1.start();
        seller2.start();
        seller3.start();
    }
}

class TicketOffice implements Runnable {
    //定义10张电影票
    int ticket = 10;
    Object obj = new Object();//这个一定要写在类离,不要写在方法李

    //写在类里面才是共享的资源,写在方法里面,每个线程都有自己的资源,就不是共享的了
    @Override
    public void run() {
        sellTicket();
    }

    //同步方法
    public synchronized void sellTicket() {
        while (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //开始卖电影票,没售出一张电影票,就自动减去1
            System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticket--) + "张票!");
        }
    }
}

参考资料:

https://www.geeksforgeeks.org/synchronized-in-java/

https://www.cnblogs.com/xckxue/p/8685675.html

阿里程序员:

https://www.jianshu.com/p/f9b1159d4fde

https://www.jianshu.com/p/2ed498b43628

https://segmentfault.com/a/1190000013512810

猜你喜欢

转载自www.cnblogs.com/majestyking/p/12437426.html