Synchronized和Static Synchronized订阅号和服务号的区别别

&场景:面试的时候经常用得到!
一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念),一个是全局锁(该锁针对的是类,无论实例多少个对象,那么线程都共享该锁)。
实例锁对应的就是synchronized关键字,而类锁(全局锁)对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。
注: static 说明了该类的一个静态资源,不管new了多少个对象,只有一份,所以对该类的所有对象都加了锁!(实践才能更好的理解)
实例锁是锁特定的实例(只要有synchronized就会去锁该实例),全局锁是锁所有的实例。
&synchronized是对类的当前实例(当前对象)进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块(注:是所有),注意这里是&类的当前实例&, 类的两个不同实例就没有这种约束了。
static synchronized恰好就是要控制类的所有实例的并发访问,static synchronized是限制多线程中该类的所有实例同时访问jvm中该类所对应的代码块。
也就是说synchronized相当于 this.synchronized,而static synchronized相当于Something.synchronized.(后面又讲解)
2.1 synchronized和static synchronized
百看不如一练,上代码先:
* Project Name:Spring0725
* File Name:TestSynchronized.java
* Package Name:work1128.singleton
* Date:日下午3:44:24
* Copyright (c) 2017, 深圳金融电子结算中心 All Rights Reserved.
package work1128.
* ClassName:TestSynchronized &br/&
* Function: 测试实例锁和类锁
日 下午3:44:24 &br/&
* @version
public class TestSynchronized {
public void test1() {
synchronized(this) {
int i = 5;
while( i-- & 0){
System.out.println(Thread.currentThread().getName() + " : " + i);
Thread.sleep(500);
} catch (InterruptedException ie){
public synchronized void isSyncA() {
int i = 5;
while( i-- & 0){
System.out.println(Thread.currentThread().getName() + " : " + i);
Thread.sleep(500);
catch (InterruptedException ie){
synchronized void isSyncB(){
int i = 5;
while( i-- & 0){
System.out.println(Thread.currentThread().getName() + " : " + i);
Thread.sleep(500);
}catch (InterruptedException ie){
public static synchronized void cSyncA(){
int i = 5;
while( i-- & 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
Thread.sleep(500);
}catch (InterruptedException ie){
public static synchronized void cSyncB() {
int i = 5;
while( i-- & 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
Thread.sleep(500);
}catch (InterruptedException ie){
public static void main(String[] args) {
final TestSynchronized myt1 = new TestSynchronized();
final TestSynchronized x = new TestSynchronized();
final TestSynchronized y = new TestSynchronized();
//同一个实例,不同的synchronized方法,对象锁有约束(同一个对象&&对象锁)&&a. x.isSyncA()与x.isSyncB()
/*Thread test1 = new Thread(new Runnable() {
public void run() {
x.isSyncA();
}, "test1");
Thread test2 = new Thread(new Runnable() {
public void run() {
x.isSyncB();
}, "test2");
//不同的实例,同一个synchronized方法,对象锁没有约束(不同的对象&&对象锁)&&b. x.isSyncA()与y.isSyncA()
Thread test1 = new Thread(new Runnable() {
public void run() {
x.isSyncA();
}, "test1");
Thread test2 = new Thread(new Runnable() {
public void run() {
y.isSyncA();
}, "test2");*/
//不同的实例,不同的static synchronized方法,类锁具有约束(不同的对象,类锁)c. x.cSyncA()与y.cSyncB()
Thread test1 = new Thread(new Runnable() {
public void run() {
x.cSyncA();
}, "test1");
Thread test2 = new Thread(new Runnable() {
public void run() {
y.cSyncB();
}, "test2");*/
//不同的实例,相同的static synchronized方法,类锁具有约束(不同的对象,类锁)c1. x.cSyncA()与y.cSyncA()
Thread test1 = new Thread(new Runnable() {
public void run() {
x.cSyncA();
}, "test1");
Thread test2 = new Thread(new Runnable() {
public void run() {
y.cSyncA();
}, "test2");
//与实例无关,对象锁和类锁互不影响&&d. x.isSyncA()与Something.cSyncA()
/*Thread test1 = new Thread(new Runnable() {
public void run() {
x.isSyncA();
}, "test1");
Thread test2 = new Thread(new Runnable() {
public void run() {
y.cSyncA();
}, "test2");*/
test1.start();
test2.start();
主要看是&this.synchronized 还是something.synchronized,& & 加锁不区分锁的位置!!!!!&&
this.synchronized 还是something.synchronized是两种不同的锁,互不影响!!!!
那么,假如有Something类的两个实例x与y,那么下列各组方法被多线程同时访问的情况是怎样的?
a. x.isSyncA()与x.isSyncB()
b. x.isSyncA()与y.isSyncA()
c. x.cSyncA()与y.cSyncB() c1. x.cSyncA()与y.cSyncA()&
d. x.isSyncA()与Something.cSyncA()
&&&&& 这里,很清楚的可以判断:
a,都是对同一个实例(x)的synchronized域访问,因此不能被同时访问。(多线程中访问实例x的不同synchronized域不能同时访问)不管锁的是同一个方法与否,有synchronized的地方就会锁该实例。
x.isSyncA()与x.isSyncB()
如果在多个线程中访问x.isSyncA(),因为仍然是对同一个实例,且对同一个方法加锁,所以多个线程中也不能同时访问。(多线程中访问x的同一个synchronized域不能同时访问)
ps:多线程中,只要是同一个对象,synchronized不管锁多少方法,对象锁都起作用。
b,是针对不同实例的,因此可以同时被访问(对象锁对于不同的对象实例没有锁的约束)
x.isSyncA()与y.isSyncA()&
ps:多线程中,不是同一个对象,对象锁没有约束。
c,因为是static synchronized,所以不同实例之间仍然会被限制,相当于Something.isSyncA()与 Something.isSyncB()了,因此不能被同时访问。(注意)
x.cSyncA()与y.cSyncB()
ps:多线程中,不同的对象,类锁具有约束性。
c1&不同的实例,相同的static synchronized方法,类锁具有约束(不同的对象,类锁)c1. x.cSyncA()与y.cSyncA()&&
那么,第d呢?,书上的 答案是可以被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同的原因。
x.isSyncA()与Something.cSyncA()
(x.isSyncA()与x.cSyncA())
ps:对象锁与类锁互不干扰,与对象无关!
个人分析也就是synchronized 与static synchronized 相当于两帮派,各自管各自,相互之间就无约束了,可以被同时访问。
其实总结起来很简单:
一个锁的是类对象,一个锁的是实例对象。
若类对象被lock,则类对象的所有同步方法全被lock;
若实例对象被lock,则该实例对象的所有同步方法全被lock
3&synchronized methods(){} 与synchronized(this){}
&synchronized methods(){} 与synchronized(this){}之间没有什么区别。
只是synchronized methods(){} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
  synchronized(syncObject) {
  //允许访问控制的代码
&synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
两种方式效率比较:
3.1 同步块synchronized(this)
代码如下:
package test01;
import java.util.concurrent.CountDownL
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
public class TestSynchronizedThis {
* @param args
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3);
final SynchonizedClass sc = new SynchonizedClass();
for(int i=0; i&3; i++){
Runnable runnable = new Runnable(){
public void run() {
cdOrder.await(); //线程阻塞,等待主线程中执行cdOrder.countDown();
sc.started();
cdAnswer.countDown();
}catch(Exception e){
e.printStackTrace();
service.execute(runnable);
//线程池执行其中的线程
Thread.sleep((long) (Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"发布执行命令");
cdOrder.countDown(); //让线程池中的线程得以执行,下面主要是统计线程池中的线程得执行时间
long beginTime = System.currentTimeMillis();
System.out.println("线程" + Thread.currentThread().getName() +
"已经发送命令,正在等待结果");
cdAnswer.await();
//等待线程池中的线程执行完毕
System.out.println("线程" + Thread.currentThread().getName() +
"已收到所有响应结果,所用时间为:" + (System.currentTimeMillis()-beginTime));
}catch(Exception e){
e.printStackTrace();
service.shutdown();
class SynchonizedClass{
public void started() throws InterruptedException{
Thread.sleep(100);//1
synchronized(this){ //同步代码块
//Thread.sleep(100);//2
System.out.println("我运行使用了 10 ms");
&synchronizedClass 执行//1处的sleep(100):
&synchronizedClass 执行//2处的sleep(100):
ps:上图的两种结果的原因在于Thread.sleep(100);是否参与了实例锁的等待过程:
//1 &&Thread.sleep(100)不在synchronized(this)的代码块中,不参与加锁机制;
//2 &Thread.sleep(100)在synchronized(this)的代码块中,参与了加锁的过程。
3.2 同步方法synchronized method()
代码如下:
package test01;
import java.util.concurrent.CountDownL
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
public class TestSynchronizedMethod {
* @param args
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3);
final SynchonizedMethodClass sc = new SynchonizedMethodClass();
for(int i=0; i&3; i++){
Runnable runnable = new Runnable(){
public void run() {
cdOrder.await();
//线程阻塞,等待主线程中执行cdOrder.countDown();
sc.started();
cdAnswer.countDown();
//每执行一次started()方法,cdAnswer减少1
}catch(Exception e){
e.printStackTrace();
service.execute(runnable);
//线程池执行其中的线程
Thread.sleep((long) (Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"发布执行命令");
cdOrder.countDown();
//让线程池中的线程得以执行,下面主要是统计线程池中的线程得执行时间
long beginTime = System.currentTimeMillis();
System.out.println("线程" + Thread.currentThread().getName() +
"已经发送命令,正在等待结果");
cdAnswer.await();
//等待线程池中的线程执行完毕
System.out.println("线程" + Thread.currentThread().getName() +
"已收到所有响应结果,所用时间为:" + (System.currentTimeMillis()-beginTime));
}catch(Exception e){
e.printStackTrace();
service.shutdown();
class SynchonizedMethodClass{
public synchronized void started() throws InterruptedException{
Thread.sleep(100);//执行其它逻辑消耗时间
synchronized(this){
System.out.println("我运行使用了 10 ms");
运行结果如下:
对比3.1代码1与3.1可以看到 &&synchronized methods(){} 与synchronized(this){}&两者相差:201ms。
其实这两种锁机制都是实例锁,出现时间相差的原因是,synchronized(this){}可以在方法内部部分加锁,同步机制更加灵活,可以设置不需要加锁的部分,故而效率会高些;
synchronized methods(){} 控制的是整个方法体,所以方法里面的所有内容都会参与加锁。
&对比说明同步代码块比同步方法效率更高。
除了修饰方法之外,还可以修饰代码块,一共有以下5种用法。
synchronized(this){
//互斥代码
这里的this指的是执行这段代码的对象,synchronized得到的锁就是this这个对象的锁,这种写法等价于我们上一篇博客中讨论的:
public synchronized void func(){
//互斥代码
二、A.class
synchronized(A.class){
//互斥代码
这里A.class得到的是A这类,所以synchronized关键字得到的锁是类的锁,这种方法同下面的方法功能是相同的:
public static synchronized void fun(){
//互斥代码
所有需要类的锁的方法等不能同时执行,但是它和需要某个对象的锁的方法或者是不需要任何锁的方法可以同时执行。
&三、object.getClass()
synchronized(object.getClass){
//互斥代码
这种方法一般情况下同第二种是相同,但是出现继承和多态时,得到的结果却是不相同的。所以一般情况下推荐使用A.class的方式。
&四、object
synchronized(object){
//互斥代码
这里synchronized关键字拿到的锁是对象object的锁,所有需要这个对象的锁的方法都不能同时执行。
public class Trans {
private Object lock = new Object();
public void printNum(int num){
synchronized (lock) {
System.out.print(Thread.currentThread());
for(int i=0;i&25;i++){
System.out.print(i+" ");
System.out.println();
class MyThread implements Runnable {
private int
public MyThread(Trans trans, int num) {
this.trans =
this.num =
public void run() {
while (true)
trans.printNum(num);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
public class Test {
public static void main(String[] args) {
Trans t = new Trans();
Trans t1 = new Trans();
Thread a = new Thread(new MyThread(t, 1));
Thread b = new Thread(new MyThread(t1, 2));
a.start();
b.start();
在上边的例子中试图使用这种方法达到互斥方法打印方法,但是事实是这样做是没有效果的,因为每个Trans对象都有自己的Object对象,这两个对象都有自己的锁,所以两个线程需要的是不同锁,两个锁之间没有任何相互作用,不会起到同步作用。
五、static object
上边的代码稍作修改就可以起到互斥作用,将Trans类中Object对象的声明改为下面这样:
private static Object lock = new Object();
这样不同的类使用的就是同一个object对象,需要的锁也是同一个锁,就可以达到互斥的效果了。
经过两篇博客的介绍,我们详细的讨论了synchronized关键字的用法,看似非常复杂,其实抓住要点之后还是很好区分的,只要看synchronized获得的是哪个对象或者类的锁就行啦,其他需要这个锁的方法都不能同时执行,不需要这个锁的方法都能同时执行。
最后还要告别一个误区,相信大家都不会再犯这种错误了,synchronized锁住的是一个对象或者类(其实也是对象),而不是方法或者代码段。
1、 synchronized关键字的作用域有二种:
1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程中不同的实例对象(或者同一个实例对象)同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/}(或者synchronized(obj){/*区块*/}),它的作用域是当前对象;
3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;& 
在使用synchronized关键字时候,应该尽可能避免在synchronized方法或synchronized块中使用sleep或者yield方法,因为synchronized程序块占有着对象锁,你休息那么其他的线程只能一边等着你醒来执行完了才能执行。不但严重影响效率,也不合逻辑。
同样,在同步程序块内调用yeild方法让出CPU资源也没有意义,因为你占用着锁,其他互斥线程还是无法访问同步程序块。当然与同步程序块无关的线程可以获得更多的执行时间。(待补充)
阅读(...) 评论()> 博客详情
摘要: synchronized与static synchronized,静态方法的同步与普通方法的同步
上次被问到synchronized与static synchronized的区别,虽然知道有区别,但是愣了半晌没想出来理由在哪里,温故而知新,特此记录。
synchronized需要持有对象锁,synchronized持有的是实例对象的锁,因此其只对同一实例保证同步,若需要对所有对象都保持同步,那就需要static synchronized方法了,在class文件被jvm加载之后其实也是一个class对象,static synchronized所持有的便是class对象的锁,而jvm基本能够保证class只被加载一次,也就是只有一个class对象,那么就可以保证该class所有的实例对象操作都能正确同步。
再说到abstract与synchronized,因为abstract申明的方法是没有实现的,而synchronized方法是同步一个方法内的操作,隐含的意思就是方法必须有实现,因此两者不能同时应用于一个方法的申明。
另外,abstract与static、abstract与native也不能同时用于申明一个方法,因为static方法在class文件被加载即被初始化载入内存,而abstract申明的无实现的方法无从谈起初始化;native指示方法是由本地方法,由jvm通过底层操作系统实现,abstract则指示方法由子类实现,两者指示的方法实现都不同,当然也不能同时用了。
package&org.mxjun.
public&abstract&class&HierarchicalTest&{
&public&abstract&void&test1();
&//被注释掉的方法无法通过编译
&//public&static&abstract&void&test2();
&//public&synchronized&abstract&void&test3();
&//public&native&abstract&void&test4();
&public&static&synchronized&void&test5()&{
&&System.out.println("test5");
&public&static&void&main(String[]&args)&{
&&test5();
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)java synchronized同步静态方法和同步非静态方法的区别与举例
时间: 09:53:28
&&&& 阅读:3243
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&
synchronized关键字是java并发编程中为了解决线程对共享资源的竞争造成错误,而提供的解决方案。synchronized关键字有两种用法,一种是只用于方法的定义中,另外一种是synchronized块,我们不仅可以使用synchronized来同步一个对象变量,你也可以通synchronized来同步类中的静态方法和非静态方法。那么问题来了,同步静态方法与动态方法有什么区别呢?看完下面这个例子或许你就明白了。public class test2 {
 public static int count = 0;
public static synchronized
void inc() {
public synchronized
void inc2() {
public static void main(String[] args) {
//同时启动1000个线程,去进行i++计算,看看实际结果
for (int i = 0; i & 10000; i++) {
new Thread(new Runnable() {
public void run() {
test2 t=new test2();
&span style=&white-space:pre&& &/span&test2.inc();
//同步静态方法&span style=&white-space:pre&&
&/span&t.inc2();//同步动态方法&span style=&white-space:pre&&
&/span&}&span style=&white-space:pre&& &/span&} &span style=&white-space:pre&& &/span&Thread.sleep(1000);&span style=&white-space:pre&& &/span&System.out.println(&结果: &+count);
}}在上面例子中,分别运行test2.inc()与t.inc2(),发现,当同步静态方法时,结果始终为10000,而当运行同步动态方法时,结果则可能不为10000.
究其原因,调用synchronized非static方法加到当前对象上,static方法加到类的Class对象上。由于在Main中的循环每一次动创建一个test2对象,所以运行非静态方法inc2时,加锁的对象只是当前线程中的对象,实际上并没有实现对其它线程中test2对象的限制,因此可能出现多个对象同时写count,而static方法是对class对象加锁,对该对象中的包括static变量的访问都会受到同步的控制。
标签:&&&&&&&&&&&&&&&原文地址:http://blog.csdn.net/yunfuyiren/article/details/
&&国之画&&&& &&&&chrome插件&&
版权所有 京ICP备号-2
迷上了代码!博客分类:
synchronized(this)与synchronized(static XXX)的区别了,synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例。
浏览: 443 次
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 32位和64位的区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信