【多线程】线程中的同步锁synchronized

时间:2021-04-09 13:02:19
当多个线程同时执行时,由于cpu是随机分片的,所以,一个线程在执行过程中被另一个线程打断的情况是经常发生的。
这在某些情况下是会影响到正常的程序的输出结果的。比如银行转账一个人的账户在转账时是不能允许同时有另外一个线程也在执行的。
这就是线程同步要解决的问题。
通常发生在存在共享数据的时候。如果没有共享数据,就不会出现加锁的问题。

线程不同步问题引入

    public class TestSync implements Runnable{

    Timer timer=new Timer();//都是同一个对象
    public static void main(String[] args){
        TestSync test=new TestSync();
        Thread t1=new Thread(test);
        Thread t2=new Thread(test);
        t1.setName("t1");
        t2.setName("2");
        t1.start();
        t2.start();
    }

    public void run(){
        timer.add(Thread.currentThread().getName());
    }
}

class Timer{
    private static int num=0;
    public void add(String name){   
        num++;
        try{
            //这里的sleep只是放大了效果,如果没有sleep,这种被打断也是存在的。
            Thread.sleep(1);//1睡眠,2去执行
        }catch(InterruptedException e){
            return;
        }
        System.out.println(name+"你是第"+num+"个使用timer的线程");
    }
}
执行上面的小程序,我们发现执行的结果是:
thread-0你是第2个使用timer的线程
thread-1你是第2个使用timer的线程
分析其原因:是在执行第一个线程的过程中,当执行到num++时,这个时候num=1,但是还没打印出结果时,cpu就去执行第二个线程了,
这个时候又执行了num++这个时候num=2了,同时cpu又去执行第一个线程开始打印结果,然后再去打印第二个线程的结果,就出现上述这种情况了。
那么,为了解决这种问题,我们就需要用线程同步的思想,让线程1完全执行完以后,再去执行线程2。因为两个线程之间存在共享变量。
所以不能允许两个线程同时操作一个变量。

synchronized

其中一种解决上述问题的就是通过synchronized同步锁来实现线程同步。
class Timer{
    private static int num=0;
    public  synchronized void add(String name){
        //synchronized(this){
        num++;
        try{
            Thread.sleep(1);
        }catch(InterruptedException e){
            return;
        }
        System.out.println(name+"你是第"+num+"个使用timer的线程");
        //}
    }
}
可以实现同步块的方式,也可以使用同步方法的方式。在这里都是可以的。

synchronized个人理解:

同步锁,就好像拥有一个房间的一把锁一样,只有你拿到这把锁的钥匙,那么你才能进入这个房间。
同步锁可分为很多级别的,类级别的,方法级别的和代码块级别的。
其中方法级别和代码块级别的加锁都是针对访问的对象内部加锁的。如果一个对象的某一个方法加锁了,
那么这个对象还是可以访问其他没有加锁的方法或者属性的。而其他对象(新new出来的对象)仍然可以同时访问当前这个加锁的方法。
当然这样的话,线程之间的对象就不是共享的了。
而类级别的锁,是针对于同一个类不同的访问对象。这样只要一个实例对象拥有了这个类的锁,那么其他实例对象是不能拥有这个类的锁的。

以上是我对synchronized这个同步锁的理解。