作者专注于Java、架构、Linux、小程序、爬虫、自动化等技术。 工作期间含泪整理出一些资料,微信搜索【程序员高手之路】,回复 【java】【黑客】【爬虫】【小程序】【面试】等关键字免费获取资料。技术交流、项目合作可私聊:shuhao-99999。
目录
前言
synchronized可以为任意对象加锁,用法比较灵活,语法如下
(1)修饰代码块,作用于调用的对象;
(2)修饰方法,作用于调用的对象;
(3)修饰静态方法,作用于所有对象;
(4)修饰类,作用于所有对象。
synchronized取得的锁都是对象锁,而不是把一段代码(或者方法)当成锁!
使用synchronized时,应该注意以下细节问题:
1、synchronized锁的重入性
如下列代码所示,类似于ReentrantLock
在method1中没有释放锁的情况下,可以继续调用synchronized修饰的method2
如下列代码所示,在子类与父类之间相互调用也运用了synchronized的重用性
public class FatherSon { static class Father { public int num = 10; public synchronized void method1(){ try { num --; System.out.println("Father num = " + num); Thread.sleep(100); } catch (Exception e) { // TODO: handle exception } } } static class Son extends Father { public synchronized void method2(){ try { while (num >0) { num --; System.out.println("Son num = " + num); Thread.sleep(100); this.method1(); } } catch (Exception e) { // TODO: handle exception } } } public static void main(String[] args) { Thread t1 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub Son son = new Son(); son.method2(); } }, "t1"); t1.start(); } }
2、不要使用字符串常量作为锁
如下列代码所示,使用了字符串常量作为锁,那么t1和t2运行之后将会一直在t1中出现死循环,t2永远拿不到锁!
解决:可以使用 new String("字符串常量") 作为锁
3、锁对象的改变问题
如下列代码所示,使用synchronized锁住了一个对象,并且在代码里重新new了一个对象,导致锁对象改变。
这样在t1还没有运行完代码的时候,t2就已经可以拿到锁了,显然会出现问题!
解决:不要改变锁对象(但是改变对象的属性对代码不会有影响,比如锁是一个人,那么可以改变这个人的身高、年龄等)
public class ChangeLock { Object obj = new Object(); public void method(){ synchronized(obj){ try { System.out.println("当前线程:" + Thread.currentThread().getName() + "开始"); //从这里改变锁对象 obj = new Object(); Thread.sleep(3000); System.out.println("当前线程:" + Thread.currentThread().getName() + "结束"); } catch (Exception e) { // TODO: handle exception } } } public static void main(String[] args) { final ChangeLock cl = new ChangeLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub cl.method(); } }, "t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub cl.method(); } }, "t2"); t1.start(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t2.start(); } }