夜光带你走进 Java 成神之路(四十)擅长的领域

夜光序言:

 

如果心灵看不到春日和煦的阳光,痛苦像毒蛇一样缠绕于你的心房。人生短暂呵,要勇敢地去追寻梦想,在短暂的生命长河中留下点点帆影。

 

正文:

                           以道御术 / 以术识道

Synchronized和Lock的区别

并发编程中,锁是经常需要使用的。
在开发中我们常用的锁有两种Synchronized和Lock。

线程安全问题

线程安全是在多线程编程中
有可能会出现同时访问同一个 共享、可变资源 的情况
始终都不会导致数据破坏以及其他不该出现的结果。
这种资源可以是一个变量、一个对象、一个文件等。

    共享:多个线程可以同时访问该共享变量。
    可变:数据在生命周期中可以被改变。


内置锁

package 单例问题与线程安全性问题;

public class Singleton {

    //私有化构造方法
    private Singleton(){ }

    //夜光:有饿汉式和懒汉式两种区别
    //首先我们说,饿汉式,创建的过程中就okay了

    private static Singleton instance = new Singleton();
    

    public static Singleton getInstance(){
        return instance;
    }

}

package 单例问题与线程安全性问题;

//夜光,我们之前写了一个饿汉式
//这里,我们写一个懒汉式
public class Singleton1 {

    //首先,我们要有一个私有化的构造方法
    private Singleton1(){

    }

    private static Singleton1 instance;

    public static Singleton1 getInstance(){
        if (instance == null)  //夜光:等于空的时候,创建
            instance = new Singleton1();
        return instance;
    }


}

package 单例问题与线程安全性问题;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiThreadMain {

    public static void main(String[] args) {
        //先写上这行代码
        ExecutorService threadPool = Executors.newFixedThreadPool(20); //夜光:给个值20

        for(int i=0;i<20;i++){
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    //我们输出一下
                    System.out.println(Thread.currentThread().getName() +":"+ Singleton1.getInstance());
                }
            });
        }

    }

}

package 自旋锁死锁重入锁;

//写一个测试案例
public class Demo {

    //同步锁
    public synchronized void a(){
        System.out.println("a");
        //在a方法里面调用b方法
        b();
    }

    //同步锁
    public synchronized void b(){
        System.out.println("b");
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {  //我们需要实现一个接口
            @Override
            public void run() {
                Demo d = new Demo(); //先实例化一个对象
                d.a();

            }
        }).start();
    }


}

package 自旋锁死锁重入锁;

import java.util.Random;

//我们再写一个例子
//多个线程执行完毕之后,打印一句话
public class Demo02 {

    public static void main(String[] args) {
          new Thread(new Runnable() {
              @Override
              public void run() {
                  System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                  try {
                      Thread.sleep(new Random().nextInt(2000));
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }

                  System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
              }
          }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
            }
        }).start();



        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
            }
        }).start();

        System.out.println("所有的线程执行完毕了~~");


    }


}

package 自旋锁死锁重入锁;

import java.util.Random;

//我们再写一个例子
//多个线程执行完毕之后,打印一句话
public class Demo02 {

    public static void main(String[] args) {
          new Thread(new Runnable() {
              @Override
              public void run() {
                  System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                  try {
                      Thread.sleep(new Random().nextInt(2000));
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }

                  System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
              }
          }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
            }
        }).start();



        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行~");

                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "线程执行完毕了~~");
            }
        }).start();

        while(Thread.activeCount()==1) {//当前活动线程的数量
            //活动线程只剩下主线程,我们就认为执行完毕了
            System.out.println("所有的线程执行完毕了~~");
        }


    }


}

上图很不给面子,没有私有,那我们加点语句,写上一个睡眠的

package 自旋锁死锁重入锁;

public class Demo03 {

    private Object obj1 = new Object();
    private Object obj2 = new Object();

    //方法a
    public void a(){
        synchronized (obj1){
            synchronized (obj2){
                System.out.println("Genius Team  -- a");
            }
        }
    }

    //方法b
    public void b(){
        synchronized (obj2){
            synchronized (obj1){
                System.out.println("Genius Team  -- b");
            }
        }
    }


    //死锁发生之后,在java虚拟机里面就死了~
    public static void main(String[] args) {

        Demo03 d = new Demo03();

        new Thread(new Runnable() {  //我们创建一个线程
            @Override
            public void run() {
                d.a();

            }
        }).start();

        new Thread(new Runnable() {  //我们创建一个线程
            @Override
            public void run() {
                d.b();

            }
        }).start();

    }


}

package 自旋锁死锁重入锁;

public class Demo03 {

    private Object obj1 = new Object();
    private Object obj2 = new Object();

    //方法a
    public void a(){
        synchronized (obj1){

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (obj2){
                System.out.println("Genius Team  -- a");
            }
        }
    }

    //方法b
    public void b(){
        synchronized (obj2){

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (obj1){
                System.out.println("Genius Team  -- b");
            }
        }
    }


    //死锁发生之后,在java虚拟机里面就死了~
    public static void main(String[] args) {

        Demo03 d = new Demo03();

        new Thread(new Runnable() {  //我们创建一个线程
            @Override
            public void run() {
                d.a();

            }
        }).start();

        new Thread(new Runnable() {  //我们创建一个线程
            @Override
            public void run() {
                d.b();

            }
        }).start();

    }


}

volatile被称为轻量级锁

被其修饰的变量,在线程之间是可见的
夜光:
可见,一个线程修改了这个变量值,在另外一个线程可以读到这个修改后的值

synchronized 除了线程之间互斥以外
还有一个非常大的作用,就是保证变量的可见性

package 深入理解volatile原理与使用;

//保证可见性的前提
//多个线程拿到的是同一把锁,否则是保证不了的
public class Demo {

    private int a = 1;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.a = a;
    }

    //一个线程在get,另外一个线程在set,很大情况下会出现线程安全问题
    public static void main(String[] args) {

        //我们先new一个对象出来
        Demo d = new Demo();

        new Thread(new Runnable() {
            @Override
            public void run() {
                d.setA(10);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(d.getA());
            }
        }).start();

    }

}
发布了1477 篇原创文章 · 获赞 281 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_41987706/article/details/103660496
今日推荐