美文网首页
JAVA-线程安全

JAVA-线程安全

作者: 超人TIGA | 来源:发表于2021-03-12 22:18 被阅读0次

    程序都避免不了使用线程,但是当不同的线程同时操作同一个变量、同一个对象时,如果不进行控制,那么程序的结果就极大可能不是我们想要的。

    例如:有一个变量a,初始值为0;
    线程A、线程B都分别对变量a进行累加100次,每次增加1;
    如果不加任何控制,那最后的结果就不会是200了。
    这种时候,我们就需要对相应部分的代码进行控制,就是加个锁。

    什么是锁?

    ①类锁
    以一个类来作为锁,常见于单例模式,还有修饰静态的方法。
    因为方法是静态的,也就是说这个类和方法不需要经过实例化就可以调用,所以如果要加锁控制,同样也不能要求实例化,所以叫类锁。

    /**
     * synchronized 内置🔒  JDK提供的 内部已经封装
     */
    public class GPSEngine {
    
        private static GPSEngine gpsEngine;
    
        public static synchronized GPSEngine getInstance() {
            if (gpsEngine == null) {
                // Thread-1 释放CPU执行器   Thread-0来执行了 结果 new GPSEngine   此时Thread-1获得执行资格 有 new
                gpsEngine = new GPSEngine();
            }
            return gpsEngine;
        }
    
        /*public static GPSEngine getGpsEngine() {
            if (null == gpsEngine) {
                synchronized (GPSEngine.class) { // 类锁  还没有new GPSEngine  == 没有this
                    if (null == gpsEngine) {
                        gpsEngine = new GPSEngine();
                    }
                }
            }
            return gpsEngine;
        }*/
    }
    

    ②对象锁
    区别于类锁,对象锁就是用一个对象类作为锁。

    /**
     * synchronized 内置
     *
     * 类说明:synchronized的作用
     *
     * 对象锁
     *
     */
    public class SynTest {
    
        private long count =0;
        private Object obj = new Object(); // 作为一个锁 对象锁obj
        private String str = new String(); // 作为一个锁 对象锁str
    
        public long getCount() {
            return count;
        }
    
        public void setCount(long count) {
            this.count = count;
        }
    
        // count进行累加
        public void incCount(){
    
            // T1 T2
            synchronized (obj){ // 使用一把锁
                // T0 T1 T2 == 多个线程 并发问题
                count++;
            }
        }
    
        // count进行累加
        // synchronized == 对象锁 == this
        public synchronized void incCount2(){
                count++;
        }
    
        // count进行累加
        // this == 对象锁
        public void incCount3(){
            synchronized (this){
                count++;
            }
        }
    
        // 线程
        private static class Count extends Thread{
    
            private SynTest simplOper;
    
            public Count(SynTest simplOper) {
                this.simplOper = simplOper;
            }
    
            @Override
            public void run() {
                for(int i=0;i<10000;i++){
                    simplOper.incCount(); // count = count+10000
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            SynTest simplOper = new SynTest();
    
            // 启动两个线程
            Count count1 = new Count(simplOper);
            Count count2 = new Count(simplOper);
            count1.start();
            count2.start();
    
            Thread.sleep(50);
    
            // 2w
    
            System.out.println(simplOper.count);//20000
        }
    }
    

    ③显示锁
    显示锁,其实就是自定义锁,就是说锁的行为可以由我们自己来自由控制。
    而上面的类锁和对象锁,都是由synchronize来帮我们实现的,我们不需要管太多。

    /**
     * 使用显示锁的范式
     */
    public class LockDemo {
    
        private int count = 0;
    
        // 内置锁 == this
        private synchronized  void test() {
    
        }
    
        // 内置锁 == LockDemo.class
        private static synchronized  void test2() {
    
        }
    
        private synchronized void test3() {
            // 业务逻辑,无法被中断
        }
    
    
        // 声明一个显示锁之可重入锁  new 可重入锁
        // 非公平锁
        private Lock lock = new ReentrantLock();
        
        public void incr(){
            // 使用 显示锁 的规范
            lock.lock();
            try{
                count++;
            } finally {   // 打死都要执行  最后一定会执行
                lock.unlock();
            }
        }
    
        // 可重入锁🔒  意思就是递归调用自己,锁可以释放出来
        // synchronized == 天生就是 可重入锁🔒
        // 如果是非重入锁🔒 ,就会自己把自己锁死
        public synchronized void incr2(){
            count++;
            incr2();
        }
    
        public static void main(String[] args) {
            LockDemo lockDemo = new LockDemo();
        }
    
    }
    
    死锁是怎么造成的?

    死锁就是程序被彻底锁住了,导致程序无法继续执行。
    一般死锁的原因就是synchronize嵌套使用了,避免这种情况,基本就避免了死锁。

    线程安全的应用场景

    生产者消费者模式,就是很经典的例子。
    而其中音视频的处理,就是其中之一,因为音频和视频我们需要达到同步。

    相关文章

      网友评论

          本文标题:JAVA-线程安全

          本文链接:https://www.haomeiwen.com/subject/jbhbqltx.html