当前位置: 代码迷 >> 综合 >> synchronized 加锁保证线程安全
  详细解决方案

synchronized 加锁保证线程安全

热度:28   发布时间:2023-12-17 03:23:23.0

synchronized 锁

synchronized关键字最主要有以下3种应用方式:

  • 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁

  • 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁

  • 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

 

1 实例方法加锁 (非静态方法)

使用synchronized修饰,以便保证线程安全:加了synchronized 后同时只能有一个线程访问该方法。

但如果多个实例对象操作,非静态方法不能保证线程安全。

public class AccountingSync implements Runnable{//共享资源(临界资源)static int i=0;
?/*** synchronized 修饰实例方法*/public synchronized void increase(){i++;}@Overridepublic void run() {for(int j=0;j<1000000;j++){increase();}}public static void main(String[] args) throws InterruptedException {AccountingSync instance=new AccountingSync();Thread t1=new Thread(instance);Thread t2=new Thread(instance);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}/*** 输出结果:* 2000000*/
}

2.静态方法加锁

当synchronized作用于静态方法时,其锁就是当前类的class对象锁。当多个不同对象实例同时访问时也能保证线程安全(无论实例多少个对象,静态方法是属于类本身的,只能同时被一个对象访问)。

由于静态成员不专属于任何一个实例对象,是类成员。给静态方法加锁可以保证线程安全。

 

 

3.synchronized锁定代码块

public class AccountingSync implements Runnable{static AccountingSync instance=new AccountingSync();static int i=0;@Overridepublic void run() {//省略其他耗时操作....//使用同步代码块对变量i进行同步操作,锁对象为instancesynchronized(instance){for(int j=0;j<1000000;j++){i++;}}}public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(instance);Thread t2=new Thread(instance);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}
}

将synchronized作用于一个给定的实例对象instance,即当前实例对象就是锁对象,每次当线程进入synchronized包裹的代码块时就会要求当前线程持有instance实例对象锁,如果当前有其他线程正持有该对象锁,那么新到的线程就必须等待,这样也就保证了每次只有一个线程执行i++;操作。当然除了instance作为对象外,我们还可以使用this对象(代表当前实例)或者当前类的class对象作为锁,如下代码:

//this,当前实例对象锁
synchronized(this){for(int j=0;j<1000000;j++){i++;}
}
?
//class对象锁
synchronized(AccountingSync.class){for(int j=0;j<1000000;j++){i++;}
}

 

  相关解决方案