当前位置: 首页 > 后端技术 > Java

基于Java开发基础的Synchronized的三种应用方法

时间:2023-04-01 21:14:30 Java

synchronized的三种应用方法synchronized关键字主要有以下三种应用方法,下面分别介绍?修改实例方法,作用于当前实例为lock,在进入同步代码前获取当前实例的锁?修改静态方法,作用于当前类对象加锁,在进入同步代码前获取当前类对象的锁?修改代码块,指定锁对象,锁定给定对象,进入同步代码块前获取给定对象的锁1.synchronized作用于实例方法。我们把类变量static设置为共享资源,然后java训练多个线程去修改它。修改的意思是:先读取,计算,再写入。那么这个过程就不是原子的,多线程操作就会存在争用共享资源的问题。我们在实例方法中加上synchronized,那么当同一个实例执行这个方法的时候,就可以抢到锁并执行了。publicclassAccountingSyncimplementsRunnable{//共享资源(关键资源)staticinti=0;/***synchronized修饰的实例方法*/publicsynchronizedvoidincrease(){i++;}@Overridepublicvoidrun(){for(intj=0;j<1000000;j++){增加();}}publicstaticvoidmain(String[]args)throwsInterruptedException{AccountingSyncinstance=newAccountingSync();线程t1=新线程(实例);线程t2=新线程(实例);t1.开始();t2.开始();t1.join();t2.join();System.out.println(i);}/***Outputresult:*2000000*/}上面代码中启动了两个线程操作共享变量,两个线程执行同一个实例对象。如果不加synchronized,这里i++不是原子操作,操作先读值再写新值。如果两个线程都读取i=5,则线程1写入i=6。线程2后面写,也是写了i=6,不是我们期望的i=7。添加synchronized修改后,线程安全,线程必须获取这个锁才能进行读写。注意我们的synchronized修改的是类方法,锁是实例。多个线程在操作不同实例时,会使用不同实例的锁,无法保证修改静态变量的顺序。公共类AccountingSyncBad实现Runnable{staticinti=0;publicsynchronizedvoidincrease(){i++;}@Overridepublicvoidrun(){for(intj=0;j<1000000;j++){increase();}}publicstaticvoidmain(String[]args)throwsInterruptedException{//newnewinstanceThreadt1=newThread(newAccountingSyncBad());//new新实例Threadt2=newThread(newAccountingSyncBad());t1.开始();t2.开始();//join含义:当前线程A等待thread线程终止后才从thread.join()返回t1.join();t2.join();System.out.println(i);}}上面代码中,两个线程持有不同的对象实例,也就是使用不同的锁,所以不会互斥访问共享资源,就会出现线程安全问题。2.当synchronized作用于静态方法时,synchronized作用于静态方法时,锁是当前类到类对象的锁。由于静态成员变量不独占任何实例对象,是类成员,所以可以通过类对象锁来控制静态成员的并发操作。3、synchronized同步代码块除了可以使用关键字修饰实例方法和静态方法外,还可以使用synchronized代码块。publicclassAccountingSyncimplementsRunnable{staticAccountingSyncinstance=newAccountingSync();staticinti=0;@Overridepublicvoidrun(){//省略其他耗时操作....//使用同步代码块同步变量i操作,锁对象是instancesynchronized(instance){for(intj=0;j<1000000;j++){i++;}}}publicstaticvoidmain(String[]args)throwsInterruptedException{Threadt1=newThread(instance);线程t2=新线程(实例);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}上面的代码将Synchronized作用于给定的实例对象实例,即当前实例对象是一个锁对象。线程每次进入synchronized,包装成代码块,都会要求当前线程持有instance实例对象锁。如果其他线程当前持有对象锁,则新到达的线程必须等待,从而保证一次只有一个线程执行i++操作。当然也可以用this或class{for(intj=0;j<1000000;j++){i++;}}