java synchronized关键字浅探
synchronized 是 java 多线程编程中用于使线程之间的操作串行化的关键字。这种措施类似于数据库中使用排他锁实现并发控制,但是有所不同的是,数据库中是对数据对象加锁,而 java 则是对将要执行的代码加锁。
在 java 中使用 synchronized 关键字时需要注意以下几点:
1.synchronized 是针对同一个资源的访问作出限制。这是出现该关键字的原因。
2.对于类而言,某一个线程执行到一个 synchronized 修饰的类方法或者类方法中的代码段时,该方法或者代码段就被加上互斥锁,同时该类中的所有使用 synchronized 修饰的类方法或者类方法中的代码段都被加上互斥锁,但不影响没有使用 synchronized 修饰的类方法或者类方法中的代码段,同时也不影响该线程执行这些剩余已经被加上锁的类方法或者类方法中的代码段以及其他类中的任意方法;当线程执行完被 synchronized 修饰的类方法或者类方法中的代码段后,这些互斥锁都将同时被释放。
3.对于对象而言,某一个线程执行到一个 synchronized 修饰的对象方法或者对象方法中的代码段时,情况和 2 中一样。
4. 第 3 点和第 2 点相互之间没有影响
5.synchronized() 括号内所使用的内容指示将要封锁的资源是一个类还是一个对象中的方法或者代码块。由于无法对类声明中使用 synchronized 修饰符,所以对于类而言,需要使用类似于 synchronized(ClassName.class){/*...*/} 形式或者使用 synchronized 修饰类方法
实例代码如下:
(1)Printer 类
public class Printer {
public static void printA()
{
System.out.println(Thread.currentThread() + ": invoke printA method");
synchronized(Printer.class)
{
for(int i = 0; i < 5; i++)
{
System.out.println(Thread.currentThread() + ": into printA method's loop...");
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
public synchronized void printB()
{
System.out.println(Thread.currentThread() + ": invoke printB method");
for(int i = 0; i < 5; i++)
{
System.out.println(Thread.currentThread() + ": into printB method's loop...");
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
(2)ThreadA 类
package demo;
public class ThreadA extends Thread{
Printer p = null;
public ThreadA(Printer p)
{
super("ThreadA");
this.p = p;
}
public void run()
{
//p.printA();
Printer.printA();
}
}
(3)ThreadB 类
package demo;
public class ThreadB extends Thread{
Printer p = null;
public ThreadB(Printer p)
{
super("ThreadB");
this.p = p;
}
public void run()
{
//p.printB();
Printer.printB();
}
}
(4)MainThread 类
package demo;
public class MainThread {
public static void main(String[] args)
{
Printer p = new Printer();
ThreadA ta = new ThreadA(p);
ThreadB tb = new ThreadB(p);
ta.start();
try {
ta.join(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tb.start();
}
}
运行结果如下:
Thread[ThreadA,5,main]: invoke printA method
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadB,5,main]: invoke printB method
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
从上述结果可以看出,ThreadA 首先调用 run 方法,并且进入了 printA 方法的 for 循环块,因此先获得了互斥锁;根据 2 即可得知 ThreadB 无法执行 printB 方法。在 MainThread 中加上 join(10) 为了给 ThreadA 更多的时间以便于让它能先进入 printA 方法(这是因为 ThreadA 需要在执行完一条 pirnt 语句之后才能获得互斥锁)。如果去掉 join 语句即可验证该点。
在上述的 Printer 类添加一个 printC 方法:
public void printC()
{
System.out.println(Thread.currentThread() + ": invoke printC method");
}
创建一个 ThreadC 类:
package demo;
public class ThreadC extends Thread{
Printer p = null;
public ThreadC(Printer p)
{
this.p = p;
}
public void run()
{
for(int i = 0; i < 5; i++)
{
p.printC();
}
}
}
然后在 MainThread 中去掉 join 语句,激活线程 ThreadC,运行结果如下(各位测试时结果可能有所不同):
Thread[Thread-0,5,main]: invoke printC method
Thread[ThreadA,5,main]: invoke printA method
Thread[Thread-0,5,main]: invoke printC method
Thread[Thread-0,5,main]: invoke printC method
Thread[ThreadB,5,main]: invoke printB method
Thread[ThreadB,5,main]: into printB method's loop...
Thread[Thread-0,5,main]: invoke printC method
Thread[Thread-0,5,main]: invoke printC method
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
对于上述结果,大家可以结合 2 自己进行解释,对于 2 中剩余的观点以及对于对象的情况,也可以自行测试验证。下面验证 4 。
将 Printer 方法中的 printB 方法声明中的 static 关键字去掉,在 ThreadB 类 run 方法中使用 p.printB() 替换 Printer.printB() ,运行结果如下:
Thread[ThreadA,5,main]: invoke printA method
Thread[ThreadB,5,main]: invoke printB method
Thread[ThreadB,5,main]: into printB method's loop...
Thread[Thread-0,5,main]: invoke printC method
Thread[ThreadA,5,main]: into printA method's loop...
Thread[Thread-0,5,main]: invoke printC method
Thread[Thread-0,5,main]: invoke printC method
Thread[Thread-0,5,main]: invoke printC method
Thread[Thread-0,5,main]: invoke printC method
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
Thread[ThreadB,5,main]: into printB method's loop...
Thread[ThreadA,5,main]: into printA method's loop...
对于输出结果,各位看官可以细心分析分析
(未完待续。。。;-))
本文有参考:Devin Zhang 的博客
java synchronized关键字浅探的更多相关文章
- Java Synchronized 关键字
本文内容 Synchronized 关键字 示例 Synchronized 方法 内部锁(Intrinsic Locks)和 Synchronization 参考资料 下载 Demo Synchron ...
- Java synchronized 关键字详解
Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...
- Java synchronized关键字用法(清晰易懂)
本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面: 1.实例方法同步 2.静态方法同步 3.实例方法中同步块 4.静态方法中同步块 我觉得在学习synchro ...
- java synchronized关键字
引用其他人的一段话 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchro ...
- Java synchronized关键字的理解
转载自:http://blog.csdn.net/xiao__gui/article/details/8188833 在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环 ...
- java synchronized关键字浅析
synchronized这个关键字想必学Java的人都应该知道. 直接上例子: 方法级别实例 public class AtomicInteger { private int index; publi ...
- [java] java synchronized 关键字详解
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一 ...
- Java:synchronized关键字引出的多种锁
前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这 ...
- java synchronized关键字的底层实现
每个对象都有一个锁(Monitor,监视器锁),class对象也有锁,如果synchronized关键字修饰同步代码块,通过反编译可以看到,其实是有个monitorenter和monitorexit指 ...
随机推荐
- Android典型界面设计——ViewPage+Fragment实现区域顶部tab滑动切换
一.问题描写叙述 本系列将结合案例应用,陆续向大家介绍一些Android典型界面的设计,首先说说tab导航,导航分为一层和两层(底部区块+区域内头部导航).主要实现方案有RadioGroup+View ...
- Testin云測公布首份国内应用质量报告:半数APP平均启动时间不合格
Testin云測公布首份国内应用质量报告:半数APP平均启动时间不合格 2014/10/23 · Testin · 实验室报告 日前,Testin云測旗下质量管家Master通过随机取样1605款国内 ...
- 提高HTML5 canvas性能的几种方法
简介 HTML5 canvas 最初起源于苹果(Apple)的一项实验,现在已经成为了web中受到广泛支持的2D快速模式绘图(2Dimmediate mode graphic)的标准.许多开发者现在利 ...
- 剑指 offer set 1 二维数组中查找
总结 1. 二维数组搜索题遇到两个了, 一个是 Leetcode 上 search in 2D matrix. 那道题比较简单, 因为下一行的所有元素大于上一行的. 这道题对二维矩阵的要求比较松, 起 ...
- 对jquery的 attr()和prop()理解
jquery1.6版本后引入了prop()方法,很多时候总是混淆attr()与prop()这俩,下面分析一下这俩的区别 在此之前,先来了解一下html 的attribute和property,因为jq ...
- 云服务器 ECS Linux 误删除文件恢复方法介绍
云服务器 ECS Linux 下,rm -rf 意味着一旦删除的文件是无法挽回的.但如果在没有文件覆盖操作的前提下,可以先尝试相关方式进行文件恢复. 本文对此进行简要说明. https://help ...
- LeetCode32 Longest Valid Parentheses
题目: Given a string containing just the characters '(' and ')', find the length of the longest valid ...
- C++类设计2(Class with pointer members)
二 Class with pointer members(Class String) 1. 测试代码(使用效果) int main() { String s1(), String s2("h ...
- 小白日记48:kali渗透测试之Web渗透-XSS(二)-漏洞利用-键盘记录器,xsser
XSS 原则上:只要XSS漏洞存在,可以编写任何功能的js脚本 [反射型漏洞利用] 键盘记录器:被记录下的数据会发送到攻击者指定的URL地址上 服务器:kali 客户端 启动apache2服务:ser ...
- 第一章:Pandas概论
Series:一维数组,与Numpy中的一维array类似.二者与Python基本的数据结构List也很相近,其区别是:List中的元素可以是不同的数据类型,而Array和Series中则只允许存储相 ...