同步方法

Posted pxy-1999

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同步方法相关的知识,希望对你有一定的参考价值。

public class SellTickets implements Runnable{
    //共有100张票
    private int tickets = 100;
    private Object obj = new Object();
    private int x = 0;

    @Override
    public void run() {
        while (true) {
            //锁多条语句操作共享数据,当线程1运行进入锁时,对外相当于被锁起来,其他线程只能等待线程1运行结束才能进入。
            if (x % 2 == 0) {
                synchronized (obj) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                        tickets--;
                    }
                }
            } else {
                synchronized (obj) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                        tickets--;
                    }
                }
            }
            x++;
        }
    }
}

将上述代码中else部分使用一个单独的方法并加锁来实现:

private synchronized void SellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--;
}
}

此时来运行卖票测试类:

技术图片此时仍然会发生数据安全问题,原因在于synchronized关键字在锁方法时,锁的是一个方法,其对应的对象应该能表示本方法的——this,而在if中锁的对象仍然还是Object,所以会发生问题,将if语句中锁的对象修改为this后的代码:

synchronized (this) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                        tickets--;
                    }

此时的运行结果:

技术图片没有出现数据安全问题

那么如果我将synchronized加到静态方法上,锁对应的对象应该是什么?

分析staic关键字可以猜到,锁静态方法时,应该是要锁一个与类相关的对象——类名.class(字节码文件)

技术图片
public class SellTickets implements Runnable{
    //共有100张票
    private static int tickets = 100;
    private Object obj = new Object();
    private int x = 0;

    @Override
    public void run() {
        while (true) {
            //锁多条语句操作共享数据,当线程1运行进入锁时,对外相当于被锁起来,其他线程只能等待线程1运行结束才能进入。
            if (x % 2 == 0) {
                synchronized (SellTickets.class) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                        tickets--;
                    }
                }
            } else {
                SellTicket();
            }
            x++;
        }
    }

    private static synchronized void SellTicket() {
        if (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
            tickets--;
        }
    }
}
View Code

 技术图片运行结果也是没有问题的。

以上是关于同步方法的主要内容,如果未能解决你的问题,请参考以下文章

[工作积累] UE4 并行渲染的同步 - Sync between FParallelCommandListSet & FRHICommandListImmediate calls(代码片段

线程同步-使用ReaderWriterLockSlim类

#VSCode保存插件配置并使用 gist 管理代码片段

同步代码 [重复]

静态方法内的同步块将获取类级别锁或对象级别锁

php 测试同步片段