高并发处理之Synchronized学习(一)

Synchronized的作用
官方介绍:
同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取和写入都是通过同步方法完成的。
用一句话说出Synchronized的作用:
能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。
如果说一段代码被Synchronized所修饰,那么被修饰的这段代码,就会以原子的方式执行,而多个线程在执行这段代码的时候,他们不会相互干扰,不会相互影响,因为多个线程之间,并不会同时执行这段代码,只要他们不同时执行,就不会出现并发问题。
具体而言,他们是怎么做的不会同时执行的呢?他们是怎么知道有一个线程已经执行了呢?
他们会有一把锁,这把锁会在第一个线程执行这段代码的时候去拿到这把锁,一旦拿到这把锁的时候,他就独占这把锁,直到这个方法结束,或者达到某个条件的时候,他才会去释放这把锁,在释放这把锁的之前,其他的线程只能去等待阻塞,直到这把锁释放了,下一个线程才能执行这一段代码,所以Synchronized关键字,就是通过这样的一种方式,完成了安全并发的保护工作。

Synchronized的地位
Synchronized是JAVA的关键字,被JAVA语言原生支持
是最基本的互斥同步手段
是并发编程中元老级角色,是并发编程的必须内容

不使用并发手段会有什么后果?
编程:两个线程同时执行i++,循环执行10W次,最后结果会比预计的少
先看代码

package com.gwh.lock.test;

/**
 * 不使用并发手段带来的后果
 * 消失的请求数
 * 预期结果是200000,但是每次都会不同
 */
public class DIsappearRequest1 implements Runnable{

    public static DIsappearRequest1 instance=new DIsappearRequest1();

   public static  int i=0;

    public static void main(String[] args) {
        try {
            //创建2个线程
            Thread t1=new Thread(instance);
            Thread t2=new Thread(instance);
            t1.start();
            t2.start();
            //为保证输出是在两个线程结束后需要用到join方法 join方法是在线程1方法执行完之前都会进行阻塞,直到线程1方法执行完成后,就会执行线程2方法然后阻塞,直到线程2方法执行完成以后才会输出最终的结果
            t1.join();
            t2.join();

            System.out.println("最终的结果为:"+i);
        }catch (Exception e){
            e.printStackTrace();
        }


    }

    @Override
    public void run() {
        for (int j=0; j<100000;j++){
            i++;
        }

    }
}

先执行第一次
高并发处理之Synchronized学习(一)_第1张图片
执行第二次
在这里插入图片描述
每次都不同,也没达到预期的200000
原因:
i++,它看上去只是一个操作,实际上包含了三个动作:
1.读取i
2.将i加一
3.将i的值写入到内存中
这样一个操作被拆分为了3个,在多线程的情况下,任何一个步都有可能被打断,都有可能执行第二个线程,所以导致结果比预计的少
就好比t1线程开始执行到3,他开始执行++操作,当他执行到第二步的时候,将i变为4,然后执行第三步的时候,下一个线程执行进来,读取的i的值,同样为3,然后加一,在将值写入到内存中,写入进去的是4,上一个操作这时也执行最后一步,写入内存的也是4.这样就达不到我们想要拿到的结果。本来应该执行两次++的结果i的值应该为5,但是两次++操作完后,执行的结果却是4,这样的情况我们称之为:线程不安全

你可能感兴趣的:(java)