前面几章都是在说synchronized用于对象锁,无论是修饰方法也好修饰代码块也好,然而关键字synchronized还可以应用到static静态方法上,如果这样写,那就是对当前的*.java文件所对应的Class类进行加锁。那么接下来就来说说synchronized修饰static的最基本用法和最显而易见的特点。我写了一个小例子,代码如下:

public static void main(String[] args) {

		ThreadA a = new ThreadA();
a.setName("A");
a.start();
ThreadB b = new ThreadB();
b.setName("B");
b.start();
} public static class ThreadB extends Thread {
private Servic1 service; @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printB();
}
} public static class ThreadA extends Thread {
private Servic1 service; @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printA();
}
}
} class Servic1 {
synchronized public static void printA() { try {
System.out.println("线程" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) { e.printStackTrace();
}
} synchronized public static void printB() { System.out.println("线程" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printB");
System.out.println("线程" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB"); }
}

     运行结果如下:从结果来看,和synchronized修饰普通方法时候的执行效果没什么不同,其实本质是不一样的,synchronized修饰static方法是给改方法所在的Class类加锁,而synchronized修饰普通方法是当前方法所在的类的对象加锁。单单用一句话来描述他们的本质对有些人来说也不会有太深的体会,那么我会写几个不同场景的例子,让大家体会一下用在代码里到底有什么不一样的地方。

一开始学习多线程对象锁和类锁的时候,我自以为类比对象的范围大,所以认为用类锁既可以对类锁起作用又可以对这个类所对应的对象锁起作用,后来写了一个例子,我发现这个想法完全不对,下面我就附上这个例子,如下:

	public static void main(String[] args) {

		Service2 service = new Service2();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
ThreadC c = new ThreadC(service);
c.setName("C");
c.start(); } public static class ThreadA extends Thread { private Service2 service; public ThreadA(Service2 service) {
super();
this.service = service;
} @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printA();
}
} public static class ThreadB extends Thread { private Service2 service; public ThreadB(Service2 service) {
super();
this.service = service;
} @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printB();
}
} public static class ThreadC extends Thread { private Service2 service; public ThreadC(Service2 service) {
super();
this.service = service;
} @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printC();
}
}
} class Service2 { synchronized public static void printA() { try {
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} synchronized public static void printB() {
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printB");
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB");
} synchronized public void printC() {
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printC");
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printC");
}
}

     运行结果如下:代码中在printA()方法中有一段3000毫秒的休眠,在休眠期间,线程C执行了printC()方法,说明这两个方法的锁并不是同一把锁,所以线程A和线程C之间是异步的,也说明了一个问题,类锁虽然比对象锁的范围大,但是不是一把锁也不会起作用,再看结果,线程A和线程B一定永远都是同步的,表现在,一定是某个线程执行完释放掉这把类锁另一个线程才能得到执行的机会,所以printA()和printC()用的是同一把锁。

写到这里,第一个例子我说了类锁的用法,第二例子我证明了类锁和对象锁并是一把锁,相互不会干扰,那么下面我要说一下,“类锁”的“锁”的范围到底是多大,到底哪些锁用的是同一把“类锁”。下面我附上一段代码,如下:

	public static void main(String[] args) {

		Service3 s1 = new Service3();
Service3 s2 = new Service3();
ThreadA a = new ThreadA(s1);
ThreadB b = new ThreadB(s2);
a.setName("A");
b.setName("B");
a.start();
b.start();
} public static class ThreadA extends Thread { private Service3 service; public ThreadA(Service3 service) {
super();
this.service = service;
} @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printA();
}
} public static class ThreadB extends Thread { private Service3 service; public ThreadB(Service3 service) {
super();
this.service = service;
} @Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.printB();
}
} } class Service3 { synchronized static public void printA() { try {
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} synchronized static public void printB() {
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printB");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB");
}
}

      运行结果如下:在前几篇讲对象锁的时候,我写过一个和这个基本一样的例子,用语言描述就是有多个线程同时调用同一个类的不同对象的不同的synchronized修饰的普通方法,但是执行结果确实异步的,原因就是虽然是同一个类,但是确实不同的对象,所以这些锁之间相互之间不会影响,如果大家不明白要对比的话,可以去上http://www.cnblogs.com/chentong/p/5660801.html这里找最后一个例子。但是现在的这个例子,也是有多个线程调用同一个类的不同对象的不同synchronized修饰的static方法,执行结果确实同步的,说明这些方法的锁是同一把锁。那么也就知道了Class锁的有效范围了,Class锁可以对该类(Service3)的所以对象实例(s1、s2)起作用,前提是该类里的方法(printA、printB)用的Class锁。如果有的方法用的对象锁,也不会起作用,上一个例子已经证明了。

用关键字synchronized修饰static方法实现“Class锁”,只是其中的一种写法,还有一种实现“Class锁”的方式,下篇我会详细的介绍。

Java多线程之synchronized(四)的更多相关文章

  1. JAVA多线程之Synchronized关键字--对象锁的特点

    一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章 二,分析 s ...

  2. (二)java多线程之synchronized

    本人邮箱: kco1989@qq.com 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco github: https://github.com/kco198 ...

  3. JAVA多线程之Synchronized、wait、notify实例讲解

    一.Synchronized synchronized中文解释是同步,那么什么是同步呢,解释就是程序中用于控制不同线程间操作发生相对顺序的机制,通俗来讲就是2点,第一要有多线程,第二当多个线程同时竞争 ...

  4. Java多线程之synchronized详解

    目录 synchronized简介 同步的原理 对象头与锁的实现 锁的优化与升级 Monitor Record 锁的对比 synchronized简介 synchronized关键字,一般称之为&qu ...

  5. Java多线程之synchronized(三)

    在多线程访问同一个对象中的不同的synchronized方法或synchronized代码块的前提下,也就是“对象监控器”为同一个对象的时候,也就是synchronized的锁为同一把锁的时候,调用的 ...

  6. Java多线程之synchronized及其优化

    Synchronized和同步阻塞synchronized是jvm提供的同步和锁机制,与之对应的是jdk层面的J.U.C提供的基于AbstractQueuedSynchronizer的并发组件.syn ...

  7. JAVA多线程之synchronized和volatile实例讲解

    在多线程中,提到线程安全.线程同步,我们经常会想到两个关键字:volatile和synchronized,那么这两者有什么区别呢? 1. volatile修饰的变量具有可见性 volatile是变量修 ...

  8. java 多线程之synchronized wait/notify解决买票问题

    一.Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable):当调用线程对象的st ...

  9. Java多线程之synchronized和volatile

    概述 用Java来开发多线程程序变得越来越常见,虽然Java提供了并发包来简化多线程程序的编写,但是我们有必要深入研究一下,才能更好的掌握这块知识. 本文主要对Java提供的底层原语synchroni ...

随机推荐

  1. Fiddler [Fiddler] Connection to localhost. failed.

    原文地址:http://blog.chinaunix.net/uid-20675015-id-1899931.html 在用Fiddler调试本机的网站时,即访问http://localhost,返回 ...

  2. php数组使用技巧及操作总结

    数组,可以说是PHP的数据应用中较重要的一种方式.PHP的数组函数众多,下面是一些小结,借此记之,便于以后鉴之. 1. 数组定义 数组的定义使用 array()方式定义,可以定义空数组:<?ph ...

  3. SPOJ 705 Distinct Substrings(后缀数组)

    [题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每 ...

  4. [cpp]伯乐在线编程挑战第 0 期 – 呼叫转移系统

    题目: 描述 呼叫转移服务是一个把呼叫号码A转移到号码B的服务.举个例子:当你正在度假时,这样的系统非常有帮助.A君度假去了,那么,A君的工作电话可以通 过呼叫转移至B君.更进一步讲,当B君也正好在度 ...

  5. iOS 按钮倒计时功能

    iOS 按钮倒计时功能, 建议把按钮换成label,这样会避免读秒时闪烁 __block ; __block UIButton *verifybutton = _GetverificationBtn; ...

  6. 吝啬的国度(dfs+vector)

    吝啬的国度 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市, ...

  7. ios中的GCD

    前面我们说了block中提到它用于多线程,而gcd则是其用于多线程的典型.gcd其全称(Grand Central Dispatch) 那到底什么叫gcd,官方的解释如下: Grand Central ...

  8. Swift 中类的初始化器与继承

    首先,Swift 为类定义了两种初始化器来确保类中所有的储存属性都能得到一个初始化值.这两种初始化器就是「指定初始化器」(Designated Initializer)与「便利初始化器」(Conven ...

  9. ceph基本操作整理

    一.ceph基本操作: 启动osd.mon进程: start ceph-osd id=X start ceph-mon id=YYY 关闭osd.mon进程: stop  ceph-osd id=X ...

  10. linux之线程

    http://blog.csdn.net/lanyan822/article/details/7586845 POSIX线程数据类型: pthread_t 线程标识符: pthread_mutex_t ...