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指 ...
随机推荐
- Jquery zTree结合Asp.net实现异步加载数据
zTree结合Asp.net实现异步加载数据 实现简单操作 zTree 下载 api 访问 :http://www.ztree.me/v3/main.php 例子中用到json数据转化 newtons ...
- AllJoyn Bundled Daemon 使用方式研究
关于AllJoyn不多做介绍,请看官网:www.alljoyn.org/ 0. 问题来源: 应用程序要使用AllJoyn库,就必须启动deamon. 目前有两种方式: 使用standalone形式,单 ...
- org.apache.hadoop.conf-Configurable
从包名可以看出这个包里面都是配置相关的类:从类名上可以看出这是一个接口,或者说配置类接口.内容很少. package org.apache.hadoop.conf; /** Something tha ...
- nodejs 实现 http proxy 透明转发
这两天需要安装一个Linux虚拟机,接下来要通过 yum 来安装需要的软件. 因单位的网络需要通过代理才能访问外网,公司代理服务器:proxy.xxxx.com,给yum增加了proxy设置: # v ...
- api 翻译之AsyncTask
AsyncTask 类的简介: AsyncTask可以使UI线程更合理更简单的使用.这个类允许执行后台操作,而且可以在不使用多线程或handlers的情况下给主线程传输数据. 异步任务 被定义为在后台 ...
- Oracle基础(六) 数据类型
一.Oracle中的数据类型 Oracle中提供了丰富的数据类型,用来存储数据,主要包括: 1.字符类型:主要用来存储字符串类型的数据. 数据类型 长度 说明 CHAR(n BYTE/CHAR) 默认 ...
- 未能正确加载“radlangsvc.package,radlangsvc.vs,version=10.0.0,culture=neutra
1: 参考 http://blog.csdn.net/woaizhoulichao1/article/details/6911809 2: 开 始-->所有程序 -->Mircosoft ...
- xml格式化成json
JsonConvert.SerializeObject(model) XmlDocument doc = new XmlDocument(); doc.Loa ...
- 公用的stringUtil工具
(function(){ var ISCHINESE = /[\u4e00-\u9fa5]/; var getData = function( value , maxLenth , isStrick ...
- Chrome浏览器跨域问题
最近在学习Ionic,调试http请求的时候遇到跨域问题 解决办法:使用chrome浏览器安装这个插件:Allow-Control-Allow-Origin: *