Java多线程之synchronized(三)
在多线程访问同一个对象中的不同的synchronized方法或synchronized代码块的前提下,也就是“对象监控器”为同一个对象的时候,也就是synchronized的锁为同一把锁的时候,调用的效果就是:当前正在执行的synchronized方法或synchronized代码块的运行结果是同步的,但是对其synchronized方法或synchronized代码块来说是阻塞的。同步是因为当一个线程执行synchronized方法或代码块的时候,正常情况下,别的线程永远得不到CPU的执行机会。也就是因为别的线程永远得不到执行机会,所以其他synchronized方法和synchronized代码块没有机会被执行,造成阻塞。
其实Java还支持“任意对象”作为“对象监视器”,来实现同步的功能,这个“任意对象”大多数为实例变量或者方法形参,使用的格式为synchronized(非this对象)同步代码块。那么她的特点和synchronized(this)代码块是一样的,特点如下:在多个线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象)代码块里的代码。我写了一个小例子来证明,代码如下:
public static void main(String[] args) {
MyService1 service = new MyService1();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadB b = new ThreadB(service);
b.setName("B");
a.start();
b.start();
}
public static class ThreadA extends Thread {
private MyService1 service;
public ThreadA(MyService1 service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodA("a", "A");
}
}
public static class ThreadB extends Thread {
private MyService1 service;
public ThreadB(MyService1 service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodA("b", "B");
}
}
}
class MyService1 {
private String userName, userPassWord;
String s = new String();
public void serviceMethodA(String userName, String userPassWord) {
synchronized (s) {
try {
System.out.println("线程" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入同步块");
Thread.sleep(5000);
System.out.println("线程" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开同步块");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:从代码上可以看到,线程A和线程B访问的都是service这个对象,所以“对象监控器”为同一个对象,理论上,在这种情况,执行的结果应该是同步的,从控制台打印的结果来看,也确实是同步的。

那么synchronized(非this对象)有什么优点呢,我们假设在一个类中有很多synchronized修饰的方法,虽然可以实现同步,但是同时也形成了阻塞,这样就影响了运行效率,但是使用同步代码块非this锁就可以解决这个问题,因为非this锁和this锁是异步的,他们之间不会互相争夺锁,这样运行效率就提高了。下面看一个例子来证明这件事情,只需要在MyService1类里添加一个方法即可,然后线程B调用该方法。代码如下:
public void serviceMethodB(String userName, String userPassWord) {
synchronized (this) {
try {
System.out.println("线程" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入同步块");
Thread.sleep(5000);
System.out.println("线程" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开同步块");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果如下:由于“对象监视器”不同,所以运行的结果是异步的,这个异步说的是方法serviceMethodA和方法serviceMethodB之间是异步的,交叉执行的。

上面说过了多个线程同时访问synchronized(非this对象)代码块时,呈同步效果,也就是说必须一个线程执行完释放掉锁,另一个线程才可以执行。也说过了多个线程分别访问this锁和非this锁,呈异步效果,可以提高运行效率。接下来说一说多线程访问不同的对象是什么效果,也就是使用不同的“对象监视器”。下面看一个例子,代码如下:
public static void main(String[] args) {
MyService4 service = new MyService4();
MyObject1 object = new MyObject1();
MyObject1 object1 = new MyObject1();
//两个线程传入不同的对象
ThreadA a = new ThreadA(service, object);
a.setName("A");
ThreadB b = new ThreadB(service, object1);
b.setName("B");
a.start();
b.start();
}
public static class ThreadA extends Thread {
private MyService4 service;
private MyObject1 object;
public ThreadA(MyService4 service, MyObject1 object) {
super();
this.service = service;
this.object = object;
}
@Override
public void run() {
super.run();
service.serviceMethod(object);
}
}
public static class ThreadB extends Thread {
private MyService4 service;
private MyObject1 object;
public ThreadB(MyService4 service, MyObject1 object) {
super();
this.service = service;
this.object = object;
}
@Override
public void run() {
super.run();
service.serviceMethod(object);
}
}
}
class MyService4 {
public void serviceMethod(MyObject1 object) {
synchronized (object) {
try {
System.out.println("线程" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入同步块");
Thread.sleep(5000);
System.out.println("线程" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开同步块");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyObject1 {
}
运行结果如下:由结果可以看出来,如果使用不同的“对象监视器”,结果是异步执行的。

Java多线程之synchronized(三)的更多相关文章
- JAVA多线程之Synchronized关键字--对象锁的特点
一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章 二,分析 s ...
- JAVA多线程之Synchronized、wait、notify实例讲解
一.Synchronized synchronized中文解释是同步,那么什么是同步呢,解释就是程序中用于控制不同线程间操作发生相对顺序的机制,通俗来讲就是2点,第一要有多线程,第二当多个线程同时竞争 ...
- (二)java多线程之synchronized
本人邮箱: kco1989@qq.com 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco github: https://github.com/kco198 ...
- Java多线程之synchronized及其优化
Synchronized和同步阻塞synchronized是jvm提供的同步和锁机制,与之对应的是jdk层面的J.U.C提供的基于AbstractQueuedSynchronizer的并发组件.syn ...
- java 多线程之synchronized wait/notify解决买票问题
一.Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable):当调用线程对象的st ...
- Java多线程之synchronized详解
目录 synchronized简介 同步的原理 对象头与锁的实现 锁的优化与升级 Monitor Record 锁的对比 synchronized简介 synchronized关键字,一般称之为&qu ...
- Java多线程之synchronized(四)
前面几章都是在说synchronized用于对象锁,无论是修饰方法也好修饰代码块也好,然而关键字synchronized还可以应用到static静态方法上,如果这样写,那就是对当前的*.java文件所 ...
- JAVA多线程之synchronized和volatile实例讲解
在多线程中,提到线程安全.线程同步,我们经常会想到两个关键字:volatile和synchronized,那么这两者有什么区别呢? 1. volatile修饰的变量具有可见性 volatile是变量修 ...
- Java多线程之synchronized和volatile
概述 用Java来开发多线程程序变得越来越常见,虽然Java提供了并发包来简化多线程程序的编写,但是我们有必要深入研究一下,才能更好的掌握这块知识. 本文主要对Java提供的底层原语synchroni ...
随机推荐
- Android安装应用失败UID 和 PID
参考:http://blog.sina.com.cn/s/blog_62ef2f140101j6q2.html 安装任意第三方的一个apk,恢复出厂设置,再次安装相同的apk,提示安装失败,通过打印L ...
- 操作native window的QxtWindowSystem (好像是一个IM的一部分)
http://libqxt.bitbucket.org/doc/0.6/qxtwindowsystem.html https://github.com/psi-plus/plugins/blob/ma ...
- mysql数据库字段区分大小写的设置方法
alter table t_25_thread_info modify column thread_id varchar(8) character set utf8 collate utf8_bin;
- HDU 5787 K-wolf Number(数位DP)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5787 [题目大意] 求区间[L,R]内十进制数相邻k位之间不相同的数字的个数. [题解] 很显然的 ...
- Linux c 信号—pause、sigsuspend 的相同于区别
pause函数: 功能:让进程暂停直到信号出现 #include<unistd.h> intpause(); 函数说明:pause()会令目前的进程暂停(进入睡眠状态),直至信号 ...
- HTML5新特性之CSS+HTML5实例
1.新的DOCTYPE和字符集 HTML5的一项准则就是化繁为简,Web页面的DOCTYPE被极大的简化. <!DOCTYPE html> 同时字符集声明也被简化了: <meta c ...
- HDU1506 ( Largest Rectangle in a Histogram ) [dp]
近期情绪太不稳定了.可能是由于在找实习这个过程碰壁了吧.第一次面试就跪了,可能是我面的是一个新公司,制度不完好,我感觉整个面试过程全然不沾编程,我面试的还是软件开发-后来我同学面试的时候.说是有一道数 ...
- linux进程之fork 和 exec函数
---恢复内容开始--- fork函数 该函数是unix中派生新进程的唯一方法. #include <unistd.h> pid_t fork(void); 返回: (调用它一次, 它 ...
- 【Cocos2D-x 3.5实战】坦克大战(1)环境配置
前言: 最近课比较少,空闲时间比较多,一有时间就东想西想,想着想着就突然想到做手机游戏(android)了,学习下CoCos2d.看了一些CoCos2D的相关文档和教程,觉得是时候实战了,但是苦于没有 ...
- SAE上使用本地sql文件建表时出错解决方法
在SAE上部署网站时需要上传本地的数据库结构,我也导出了本地数据库为sql文件,但是上传到SAE上时遇到了如下错误: MySQL 返回: #1044 - Access denied for user ...