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指 ...
随机推荐
- Session丢失,都是CDN惹的祸
周六下午,正在外面吃饭,运营的同事火急火燎地给我打电话,说是网站出问题了,用户登录不了,而且这种情况也不是全部,只有部分地区有问题.没办法,只能回到家里找问题,打开代码,翻来覆去地找问题,搞了整整一下 ...
- 基于CSS3图片可倾斜摆放的动画相册
今天我们又要来分享一个CSS3动画相册.之前我们分享过一个很酷的放满女神的HTML5/CSS3相册,相册是全屏展示的.今天这款相册的特点是图片可以任意角度的倾斜摆放,就像随意放在桌面上一样.另外,当鼠 ...
- Sublime text 2下alignment插件无效的解决办法
在sublime text 2中安装了alignment插件,但使用快捷键‘ctrl+alt+a'无效,经过各种方法依然无效,最后找到了这个“Doesn't work at all for me (f ...
- 用 Gearman 分发 PHP 应用程序的工作负载
尽管一个 Web 应用程序的大部分内容都与表示有关,但它的价值与竞争优势却可能体现在若干专有服务或算法方面.如果这类处理过于复杂或拖沓,最好是进行异步执行,以免 Web 服务器对传入的请求没有响应.实 ...
- LeetCode34 Search for a Range
题目: Given a sorted array of integers, find the starting and ending position of a given target value. ...
- 解决Lost connection to MySQL server at 'reading initial communication packet', 的方法
今天用heidsql连接mysql时出了问题,提示:Lost connection to MySQL server at 'reading initial communication packet 网 ...
- Frogs' Neighborhood
Frogs' Neighborhood Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 7920 Accepted: 33 ...
- ios-uitableviewcell展开
#import <UIKit/UIKit.h> @interface ZSDHelpCell : UITableViewCell @property (weak, nonatomic) I ...
- 怒刷DP之 HDU 1160
FatMouse's Speed Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Su ...
- tornado 信号处理
一般情况下,对于线上的程序,我们是不能采取kill -9 来杀掉进程的 因为程序可能有未处理完的程序,如果贸然采取kill -9可能会导致数据不一致 如果需要关闭程序怎么办呢,一般情况下我们采取信号技 ...