Java线程同步方法与代码块

版权声明:欢迎转载,转载请注明出处哦! https://blog.csdn.net/qq_41647999/article/details/88368663

目录直通车

一、同步代码块

二、 同步方法


一、同步代码块

sysnchronized(同步监视器){

   // 需要被同步的代码块(即为共享数据的代码)

}

1) 共享数据:多个线程共同操作的同一个数据(变量) 

2) 同步监视器:有一个类的对象来充当。哪个线程获取此监视器,谁就去执行大括号里被同步的代码。俗称:锁。要求所有的线程共用同一把锁。

下面提供一个用同步代码块的方式解决数据共享的安全问题:

实例

class W implements Runnable{
    int ticket = 100;
    // Object obj = new Object();
    public void run(){
        while(true) {
            /*
              在继承中一定要慎用this
              严格控制:要求所有的线程共用同一把锁,
              也就是说这个this代表同一个对象的时候才能够使用。
             */
            synchronized (this) {
                if (ticket > 0) {
                    try{
                        Thread.currentThread().sleep(100);
                        System.out.println(Thread.currentThread().getName() + "售票,余票为:" + ticket--);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
public class TestThreadSecurity {
    public static void main(String[] args){
        W window = new W();
        Thread window1 = new Thread(window);
        Thread window2 = new Thread(window);
        Thread window3 = new Thread(window);

        window1.setName("窗口1");
        window2.setName("窗口2");
        window3.setName("窗口3");

        window1.start();
        window2.start();
        window3.start();
    }
}

二、 同步方法

将操作共享数据的方法声明为sysnchronized。即此方法,能够保证其中一个线程执行此方法时,其它线程在外等待直至此线程执行完此方法。

扫描二维码关注公众号,回复: 5741714 查看本文章

同步方法的锁:this。

class Win implements Runnable{
    int ticket = 100;
    // Object obj = new Object();
    public void run(){
        while(true){
            show();
        }
    }
    public synchronized void show(){
        if (ticket > 0 ){
            try{
                Thread.currentThread().sleep(10);
                System.out.println(Thread.currentThread().getName()+"售票,余票为:"+ticket--);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

public class TestThreadSecurity2 {
    public static void main(String[] args){
        Win window = new Win();
        Thread window1 = new Thread(window);
        Thread window2 = new Thread(window);
        Thread window3 = new Thread(window);

        window1.setName("窗口1");
        window2.setName("窗口2");
        window3.setName("窗口3");

        window1.start();
        window2.start();
        window3.start();
    }
}

 这里还涉及到一个互斥锁的概念。

先了解一下单例模式:https://blog.csdn.net/qq_41647999/article/details/83447936

单例模式一般用于比较大、复杂的对象,只初始化一次,应该还有一个private的构造函数,使得不能用new来实例化对象,只能调用getInstance方法来得到对象,而getInstance保证了每次调用都返回相同的对象。

这里在举一个实例,解释在代码里:

class Singleton{
    private Singleton(){

    }
    /*
    这里存在一个问题, 两个线程(A、B)分别调用getInstance方法,
    首次调用的时候,instance肯定为null,A在创建Singleton之前被挂起,
    线程B进入之后也被挂起,当前的instance仍然为null。此时A继续执行
    创建一个Singleton对象,假设此时在内存中的地址为1111,线程B执行之后
    也会创建一个对象,大家肯定都知道在内存中的值一定不为1111,
    像这样返回出去的判断相等不相等的时候就有问题了。为什么呢?因为在这里的instance
    只能够new一次,这种情况却new了两次。
     */
    private static Singleton instance = null;
    /*
    这里为什么要判断一次instance为null?
    假设这里只有一家华为手机店(这里的代码块),店里面只有一台mate20,
    门口排了一大堆的人(线程)来买mate20,第一个人肯定买的到,后面的人
    就买不到了,但是没有人告诉后面的人卖完了,每个人还得进店一次。所以
    这里的instance不为null的时候,就是告诉后面的线程,说这里的mate20
    已经卖完了,不用排队了。
    */
    if (instance == null ){
    public static Singleton getInstance(){
        if (instance == null ){
            instance = new Singleton();
        }
        return instance;
    }
}
}

public class TestSingleton {
    public static void main(String[] args) {
        /*
        getInstance在单例模式(保证一个类仅有一个实例,
        并提供一个访问它的全局访问点)的类中常见,
        用来生成唯一的实例,getInstance一般是static的
         */
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2);
    }
}

上例BUG修复

class Singleton2{
    private Singleton2(){

    }

    private static Singleton2 instance = null;
    public static Singleton2 getInstance() {
        /*
        1、 static里面不能使用this
        2、 关于解决懒汉式的线程安全问题,需要使用同步机制
        3、 对于静态方法而言,使用当前类本身充当锁
         */
        synchronized (Singleton2.class) {
            /*
            关于这里为什么使用Singleton2.class为什么能行,涉及到反射的知识点。
             */
            if (instance == null) {
                instance = new Singleton2();
            }
            
        }
        return instance;
    }
}

public class TestSingleton2 {
    public static void main(String[] args) {
        Singleton2 s1 = Singleton2.getInstance();
        Singleton2 s2 = Singleton2.getInstance();
        System.out.println(s1 == s2);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41647999/article/details/88368663