java之同步锁---synchronized


1.背景

  前几天线上项目出现一个问题,由于并发问题,导致服务器集群中的部分服务器中的数据没有更新。经过review代码,发现没有进行数据的同步操作。最后使用synchronize解决了问题。解决问题后,在空余时间对synchronized的应用进行了研究。

2.synchronized介绍

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种: 
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象; 
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象; 
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

3. 示例

3.1 synchronized修饰代码块

如果多个线程访问的是同一个实例对象,则会出现等待,如果多个线程访问的都是不同的实例对象,则不会出现等待

3.1.1 synchronized(this)

代码如下:

 

 
 
public class SyncBlock implements Runnable{
    private static Integer count; public SyncBlock() { // TODO Auto-generated constructor stub count = 0; } public int getCount(){ return count; } @Override public void run() { // TODO Auto-generated method stub System.out.println("当前执行的程序:"+Thread.currentThread().getName()); synchronized(this) { for (int i = 0; i < 5; i++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args){ SyncBlock syncBlock = new SyncBlock(); Thread th1 = new Thread(syncBlock,"第一集团军"); Thread th2 = new Thread(syncBlock,"第二集团军"); th1.start(); th2.start(); } }
 

 

执行结果如下:


通过执行结果可以看出,同步锁机制生效。synchronized(this)使得两个线程同步等待。在main函数中增加三行代码
 
public static void main(String[] args){
		SyncBlock syncBlock = new SyncBlock();
		SyncBlock syncBlock3 = new SyncBlock();
		Thread th1 = new Thread(syncBlock,"第一集团军");
		Thread th2 = new Thread(syncBlock,"第二集团军");
		Thread th3 = new Thread(syncBlock3,"第三集团军");
		th1.start();
		th2.start();
		th3.start();
	}

执行结果如下:

通过执行结果可以看出,线程1和线程2之间出现了等待,线程1执行完之后执行线程2,而线程3与线程1和2之间没有等待。这是因为线程1和线程2是监视的同一个SyncBlock对象syncBlock,而线程3监视的是独立的对象syncBlock3。也就是说,synchronized(this)对于线程3与线程1和2,锁的是不同对象,所以彼此之间无法同步。

3.1.2 静态变量synchronized(this.count)

锁的对象是整型的实例对象count,如果count对象值是固定不变的,则所有线程之间都会等待,如果count是变化的,如count++,则所有线程之间都不会等待。因为count++的结果会改变count的对象引用,所以
synchronized(count)锁定的是不同的实例对象,也就没有起到锁的作用。
修改上面的代码如下:

 1     public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("当前执行的程序:"+Thread.currentThread().getName());
 4           synchronized(count) {
 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }
13               }
14     }

执行结果如下:

如果count的值不发生改变

 1 public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("当前执行的程序:"+Thread.currentThread().getName());
 4           synchronized(count) {
 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }
13               }
14     }

执行结果如下:由于count值不发生变化,count是对多有实例对象共享,所以所有线程多会出现等待。

3.1.3  synchronized(A.class)

       A.class表示类对象。每个类都对应着一个这样的类对象,所有线程都会彼此间等待。

修改代码如下:

 1 public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("当前执行的程序:"+Thread.currentThread().getName());
 4           synchronized(SyncBlock.class) {
 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }
13               }
14     }

执行结果如下:

3.2 synchronized非静态方法

 1 synchronized public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("当前执行的程序:"+Thread.currentThread().getName()); 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }14     }

执行结果如下,与在方法在使用synchronized(this)相同。多个线程访问的是同一个实例对象,则会出现等待,如果多个线程访问的都是不同的实例对象,则不会出现等待

 3.4 synchronized静态方法

    静态方法属于类方法,不属于任一实例对象。为所有实例对象所共享。因此对于所有线程调用synchronized静态方法,彼此之间会出现等待。与synchronized(A.clsss)类似。只是作用范围不同。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM