一、synchronized有锁重入的特点,某个线程得到对象的锁后,再次请求此对象可以再次得到改对象的锁。如下示例,在method1中调用method2,在method2中调用method3,而method1、method2和method3都是加了synchronized关键字的。

 /**
* synchronized的重入
* @author alienware
*
*/
public class SyncDubbo1 { public synchronized void method1(){
System.out.println("method1..");
method2();
}
public synchronized void method2(){
System.out.println("method2..");
method3();
}
public synchronized void method3(){
System.out.println("method3..");
} public static void main(String[] args) {
final SyncDubbo1 sd = new SyncDubbo1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sd.method1();
}
});
t1.start();
}
}

二、父类和子类的方法都是synchronized的,在子类的方法中调用父类的方法,也是线程安全的。

 /**
* synchronized的重入
* @author alienware
*
*/
public class SyncDubbo2 { static class Main {
public int i = 10;
public synchronized void operationSup(){
try {
i--;
System.out.println("Main print i = " + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} static class Sub extends Main {
public synchronized void operationSub(){
try {
while(i > 0) {
i--;
System.out.println("Sub print i = " + i);
Thread.sleep(100);
this.operationSup();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Sub sub = new Sub();
sub.operationSub();
}
}); t1.start();
} }

执行结果:

三、synchronized方法内抛异常怎么处理

  throw RuntimeException打断此线程或者记录日志然后continue,选择哪种方案取决于具体业务要求。

 /**
* synchronized异常
* @author alienware
*
*/
public class SyncException { private int i = 0;
public synchronized void operation(){
while(true){
try {
i++;
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " , i = " + i);
if(i == 20){
//Integer.parseInt("a");
throw new RuntimeException();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { final SyncException se = new SyncException();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
se.operation();
}
},"t1");
t1.start();
} }

四、synchronized代码块锁,实用起来也会比较灵活

  this、class、Object都可以用来作为代码块锁

 /**
* 使用synchronized代码块加锁,比较灵活
* @author alienware
*
*/
public class ObjectLock { public void method1(){
synchronized (this) { //对象锁
try {
System.out.println("do method1..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public void method2(){ //类锁
synchronized (ObjectLock.class) {
try {
System.out.println("do method2..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} private Object lock = new Object();
public void method3(){ //任何对象锁
synchronized (lock) {
try {
System.out.println("do method3..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { final ObjectLock objLock = new ObjectLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method2();
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method3();
}
}); t1.start();
t2.start();
t3.start(); } }

五、尽量不要用String常量作为锁

如下代码只会有t1线程运行,但可以new一个String对象。

 /**
* synchronized代码块对字符串的锁,注意String常量池的缓存功能
* @author alienware
*
*/
public class StringLock { public void method() {
//new String("字符串常量")
synchronized ("字符串常量") {
try {
while(true){
System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始");
Thread.sleep(1000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
final StringLock stringLock = new StringLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t2"); t1.start();
t2.start();
}
}

六、一个对象被用作锁时,这个对象内的属性发生变化不会影响锁的使用。

 /**
* 同一对象属性的修改不会影响锁的情况
* @author alienware
*
*/
public class ModifyLock { private String name ;
private int age ; public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public synchronized void changeAttributte(String name, int age) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 开始");
this.setName(name);
this.setAge(age); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 修改对象内容为: "
+ this.getName() + ", " + this.getAge()); Thread.sleep(2000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
final ModifyLock modifyLock = new ModifyLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("张三", 20);
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("李四", 21);
}
},"t2"); t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
} }

架构师养成记--3.synchronized细节问题的更多相关文章

  1. 架构师养成记--15.Disruptor并发框架

    一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...

  2. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  3. 架构师养成记--9.future模式讲解

    什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...

  4. 架构师养成记--6.单例和多线程、ThreadLocal

    一.ThreadLocal 使用wait/notify方式实现的线程安全,性能将受到很大影响.解决方案是用空间换时间,不用锁也能实现线程安全. 来看一个小例子,在线程内的set.get就是thread ...

  5. 架构师养成记--4.volatile关键字

    volatile修饰的变量可在多个线程间可见. 如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本. public class ...

  6. 架构师养成记--35.redis集群搭建

    前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...

  7. 架构师养成记--12.Concurrent工具类CyclicBarrier和CountDownLatch

    java.util.concurrent.CyclicBarrier 一组线程共同等待,直到达到一个公共屏障点. 举个栗子,百米赛跑中,所有运动员都要等其他运动员都准备好后才能一起跑(假如没有发令员) ...

  8. 架构师养成记--11.Executor概述

    常用方法 Executors.newFiexdPool(int nThreads);固定线程数量的线程池: Executors.newSingleThreadExecutor();单个线程的线程池: ...

  9. 架构师养成记--10.master-worker模式

    master-worker模式是一种并行计算模式,分为master进程和worker进程两个部分,master是担任总管角色,worker才是执行具体任务的地方. 总体流程应该是这样的: 具体一点,代 ...

随机推荐

  1. Linux-1:安装&忘记密码&CRT连接centos 6.5

    我是在虚拟机VM安装的centos 6.5 一.Linux安装 Ctrl + Alt:鼠标退出LINUX界面 安装我是参考,当然也可以根据网上教程安装:http://oldboy.blog.51cto ...

  2. Storm基础

    Storm基本概念 Storm是一个开源的实时计算系统,它提供了一系列的基本元素用于进行计算:Topology.Stream.Spout.Bolt等等. 在Storm中,一个实时应用的计算任务被打包作 ...

  3. Windows on Device 项目实践 3 - 火焰报警器制作

    在前两篇<Windows on Device 项目实践 1 - PWM调光灯制作>和<Windows on Device 项目实践 2 - 感光灯制作>中,我们学习了如何利用I ...

  4. lambda表达式-转载

    来源:http://www.cnblogs.com/knowledgesea/p/3163725.html   前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸 ...

  5. MySQL备份还原——AutoMySQLBackup介绍

    AutoMySQLBackup是一个开源的MySQL备份脚本.可以说它是一个轻量级的备份方案,AutoMySQLBackup的安装.配置非常简单.方便.AutoMySQLBackup的sourcefo ...

  6. Linux rm删除大批量文件

    在使用rm删除大批量文件时,有可能会遭遇"参数列太长"(Argument list too long)的问题.如下所示 [oracle@DB-Server bdump]$ rm - ...

  7. chrome 浏览器的预提取资源机制导致的一个请求发送两次的问题以及ClientAbortException异常

    调查一个 pdf 打印报错: ExceptionConverter: org.apache.catalina.connector.ClientAbortException: java.net.Sock ...

  8. Tokudb 参数优化

    tokudb_row_format tokudb_fast: 使用quicklz 库的压缩模式.(推荐)tokudb_small: 使用 lzma 库的压缩模式.tokudb_zlib: 使用 zli ...

  9. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理4

    首先先加个区域,名为Admin using System.Web.Mvc; namespace AuthorDesign.Web.Areas.Admin { public class AdminAre ...

  10. 3-2 bash 特性详解

    根据马哥Linux初级 3-2,3-3,编写 1. 文字排序 不影响源文件,只是显示根据ASCII码字符升序 nano的用法, 其实这个是生成一个文本,然后就可以在里面编辑. Ctrl + o, 后回 ...