java synchronized静态同步方法与非静态同步方法,同步语句块
摘自:http://topmanopensource.iteye.com/blog/1738178
进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁。
对代码进行同步控制我们可以选择同步方法,也可以选择同步块,这两种方式各有优缺点,至于具体选择什么方式,就见仁见智了,同步块不仅可以更加精确的控制对象锁,也就是控制锁的作用域,何谓锁的作用域?锁的作用域就是从锁被获取到其被释放的时间。而且可以选择要获取哪个对象的对象锁。但是如果在使用同步块机制时,如果使用过多的锁也会容易引起死锁问题,同时获取和释放所也有代价,而同步方法,它们所拥有的锁就是该方法所属的类的对象锁,换句话说,也就是this对象,而且锁的作用域也是整个方法,这可能导致其锁的作用域可能太大,也有可能引起死锁,同时因为可能包含了不需要进行同步的代码块在内,也会降低程序的运行效率。而不管是同步方法还是同步块,我们都不应该在他们的代码块内包含无限循环,如果代码内部要是有了无限循环,那么这个同步方法或者同步块在获取锁以后因为代码会一直不停的循环着运行下去,也就没有机会释放它所获取的锁,而其它等待这把锁的线程就永远无法获取这把锁,这就造成了一种死锁现象。
详细解说一下同步方法的锁,同步方法分为静态同步方法与非静态同步方法。
所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
而所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!
而对于同步块,由于其锁是可以选择的,所以只有使用同一把锁的同步块之间才有着竞态条件,这就得具体情况具体分析了,但这里有个需要注意的地方,同步块的锁是可以选择的,但是不是可以任意选择的!!!!这里必须要注意一个物理对象和一个引用对象的实例变量之间的区别!使用一个引用对象的实例变量作为锁并不是一个好的选择,因为同步块在执行过程中可能会改变它的值,其中就包括将其设置为null,而对一个null对象加锁会产生异常,并且对不同的对象加锁也违背了同步的初衷!这看起来是很清楚的,但是一个经常发生的错误就是选用了错误的锁对象,因此必须注意:同步是基于实际对象而不是对象引用的!多个变量可以引用同一个对象,变量也可以改变其值从而指向其他的对象,因此,当选择一个对象锁时,我们要根据实际对象而不是其引用来考虑!作为一个原则,不要选择一个可能会在锁的作用域中改变值的实例变量作为锁对象!!!!
public class Foo {
    private int x = 100; 
    public int getX() {
        return x;
    } 
    public int fix(int y) {
        x = x - y;
        return x;
    }
}
public class MyRunnable implements Runnable {
    private Foo foo = new Foo(); 
    public static void main(String[] args) {
        MyRunnable r = new MyRunnable();
        Thread ta = new Thread(r, "Thread-A");
        Thread tb = new Thread(r, "Thread-B");
        ta.start();
        tb.start();
    } 
    public void run() {
        for (int i = 0; i < 3; i++) {
            this.fix(30);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " : 当前foo对象的x值= " + foo.getX());
        }
    } 
    public int fix(int y) {
        return foo.fix(y);
    }
}
运行结果:
Thread-B : 当前foo对象的x值= 40
Thread-B : 当前foo对象的x值= -20
Thread-A : 当前foo对象的x值= -50
Thread-A : 当前foo对象的x值= -80
Thread-B : 当前foo对象的x值= -80
Process finished with exit code 0
public int fix(int y) {
    synchronized (this) {
        x = x - y;
    }
    return x;
}
当然,同步方法也可以改写为非同步方法,但功能完全一样的,例如:
public synchronized int getX() {
    return x++;
}
与
public int getX() {
    synchronized (this) {
        return x;
    }
}
效果是完全一样的。
public static synchronized int setName(String name){
      Xxx.name = name;
}
等价于
public static int setName(String name){
      synchronized(Xxx.class){
            Xxx.name = name;
      }
}
public class NameList {
    private List nameList = Collections.synchronizedList(new LinkedList()); 
    public void add(String name) {
        nameList.add(name);
    } 
    public String removeFirst() {
        if (nameList.size() > 0) {
            return (String) nameList.remove(0);
        } else {
            return null;
        }
    }
}
public class Test {
    public static void main(String[] args) {
        final NameList nl = new NameList();
        nl.add("aaa");
        class NameDropper extends Thread{
            public void run(){
                String name = nl.removeFirst();
                System.out.println(name);
            }
        } 
        Thread t1 = new NameDropper();
        Thread t2 = new NameDropper();
        t1.start();
        t2.start();
    }
}
public class NameList {
    private List nameList = Collections.synchronizedList(new LinkedList()); 
    public synchronized void add(String name) {
        nameList.add(name);
    } 
    public synchronized String removeFirst() {
        if (nameList.size() > 0) {
            return (String) nameList.remove(0);
        } else {
            return null;
        }
    }
}
public class DeadlockRisk {
    private static class Resource {
        public int value;
    } 
    private Resource resourceA = new Resource();
    private Resource resourceB = new Resource(); 
    public int read() {
        synchronized (resourceA) {
            synchronized (resourceB) {
                return resourceB.value + resourceA.value;
            }
        }
    } 
    public void write(int a, int b) {
        synchronized (resourceB) {
            synchronized (resourceA) {
                resourceA.value = a;
                resourceB.value = b;
            }
        }
    }
}
假设read()方法由一个线程启动,write()方法由另外一个线程启动。读线程将拥有resourceA锁,写线程将拥有resourceB锁,两者都坚持等待的话就出现死锁。
- package com.etrip.concurrent.executor;
 - import java.util.Collections;
 - import java.util.HashMap;
 - import java.util.Iterator;
 - import java.util.Map;
 - import java.util.Map.Entry;
 - import java.util.Set;
 - /**
 - * 非静态同步方法,静态同步方法,同步语句块的使用
 - *
 - *
 - * 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁。
 - 对代码进行同步控制我们可以选择同步方法,也可以选择同步块,这两种方式各有优缺点,至于具体选择什么方式,就见仁见智了,同步块不仅可以更加精确的控制对象锁,也就是控制锁的作用域,何谓锁的作用域?锁的作用域就是从锁被获取到其被释放的时间。而且可以选择要获取哪个对象的对象锁。但是如果在使用同步块机制时,如果使用过多的锁也会容易引起死锁问题,同时获取和释放所也有代价,而同步方法,它们所拥有的锁就是该方法所属的类的对象锁,换句话说,也就是this对象,而且锁的作用域也是整个方法,这可能导致其锁的作用域可能太大,也有可能引起死锁,同时因为可能包含了不需要进行同步的代码块在内,也会降低程序的运行效率。而不管是同步方法还是同步块,我们都不应该在他们的代码块内包含无限循环,如果代码内部要是有了无限循环,那么这个同步方法或者同步块在获取锁以后因为代码会一直不停的循环着运行下去,也就没有机会释放它所获取的锁,而其它等待这把锁的线程就永远无法获取这把锁,这就造成了一种死锁现象。
 - *
 - * @author longgangbai
 - */
 - public class StaticInstanceLock {
 - private int count;
 - private static StaticInstanceLock instance=null;
 - private StaticInstanceLock(){
 - }
 - /**
 - * 静态方法的锁
 - *
 - * @return
 - */
 - public static synchronized StaticInstanceLock getInstance(){
 - if(instance==null){
 - instance=new StaticInstanceLock();
 - }
 - return instance;
 - }
 - /**
 - * 非静态方法的锁
 - * @return
 - */
 - public synchronized int getCount(){
 - return count;
 - }
 - public synchronized void setCount(int count){
 - this.count=count;
 - }
 - /**
 - * 同步语句块的使用
 - *
 - */
 - public void synmethod(){
 - //HashMap为非安全性Map
 - HashMap<String,String> hashmap = new HashMap<String,String>();
 - hashmap.put("ZH","中国");
 - hashmap.put("EN","英国");
 - hashmap.put("AM","美国");
 - hashmap.put("FR","法国");
 - //创建一个同步的对象Map
 - Map<String,String> m = Collections.synchronizedMap(hashmap);
 - Set<String> s = m.keySet(); // Needn't be in synchronized block
 - //这里同步的对象均为需要使用同步的对象如Map而非Set
 - synchronized(m) { // Synchronizing on m, not s!
 - Iterator<String> i = s.iterator(); // Must be in synchronized block
 - while (i.hasNext()){
 - foo(i.next());
 - }
 - }
 - }
 - public void foo(String entry){
 - System.out.println("StaticInstanceLock ="+entry);
 - }
 - public static void main(String[] args) {
 - StaticInstanceLock instance=StaticInstanceLock.getInstance();
 - instance.setCount(7);
 - int count = instance.getCount();
 - instance.synmethod();
 - }
 - }
 
java synchronized静态同步方法与非静态同步方法,同步语句块的更多相关文章
- Java静态同步方法和非静态同步方法
		
所有的非静态同步方法用的都是同一把锁——该实例对象本身.也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁进而执行 ...
 - 内部类访问外部类的变量必须是final吗,java静态方法中不能引用非静态变量,静态方法中不能创建内部类的实例
		
内部类访问外部类的变量必须是final吗? 如下: package com.java.concurrent; class A { int i = 3; public void shout() { cl ...
 - java 静态资源,非静态资源,父类子类,构造方法之间的初始化循序
		
java面试经常被问静态资源,非静态资源,父类子类,构造方法之间的执行顺序.下面添加两个类做个测试 class Parent { // 静态变量 public static String p_Stat ...
 - Java synchronized对象级别与类级别的同步锁
		
Java synchronized 关键字 可以将一个代码块或一个方法标记为同步代码块.同步代码块是指同一时间只能有一个线程执行的代码,并且执行该代码的线程持有同步锁.synchronized关键字可 ...
 - synchronized同步语句块
		
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长时间.在这样的情况下可以使用synchronized同步语句块来解 ...
 - Java的外部类和内部类+静态变量和非静态变量的组合关系
		
看的李刚<疯狂java讲义>,里面讲内部类的地方感觉有点散而且不全,看完之后还是不十分清楚到底怎么用,于是自己写了个程序测试了一下.看如下代码,即可知道外部类和内部类+静态成员和非静态成员 ...
 - Java中静态变量与非静态变量的区别
		
感谢大佬:https://www.cnblogs.com/liuhuijie/p/9175167.html ①java类的成员变量有俩种: 一种是被static关键字修饰的变量,叫类变量或者静态变量 ...
 - Java代码执行顺序(静态变量,非静态变量,静态代码块,代码块,构造函数)加载顺序
		
//据说这是一道阿里巴巴面试题,先以这道题为例分析下 public class Text { public static int k = 0; public static Text t1 = new ...
 - Java类加载信息的顺序:包括静态代码快、静态类变量、非静态代码快、构造方法、普通方法
		
JVM运行之前会执行一个叫做类加载器的子系统,叫做ClassLoader,那么类里面那么多“元素”,究竟是个什么顺序呢,写几行代码测试一下,通过给每个方法和代码快和静态变量打上断点来测试: class ...
 
随机推荐
- Linux的启动过程
			
Linux的启动过程,也就是Linux的引导流程,这部分主要是理论知识. Linux的开机启动过程 1.1第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的 ...
 - 4.给定一个正整数m,统计m的位数,分别打印每一位数字,再按照逆序打印出各位数字。 要求:m定义为类的属性,需定义构造函数为m赋值;当m大于99999时,输出错误信息“the number is too large”,不再执行。
			
package a; public class ShuZi { int m; public int getM() { return m; } public void setM(int m) { thi ...
 - JAVA的文件创建
			
package com.xia; import java.io.*; public class test2 { public static void main(String[] args) { //输 ...
 - 【Unity3D游戏开发】基础知识之Tags和Layers (三二)[转]
			
Tags和Layers分别表示是Unity引擎里面的标签和层,他们都是用来对GameObject进行标识的属性,Tags常用于单个GameObject,Layers常用于一组的GameObject.添 ...
 - 迪米特法则(LoD),即最少知识原则
			
解释: 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用. 重点: 在类的结构上,每个类都应当尽量降低成员 ...
 - [SAP ABAP开发技术总结]面向对象OO
			
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
 - 概念学习(Concept Learning)
			
从特殊的训练样例中归纳出一般函数是机器学习的核心问题.一般函数是对理想目标函数的函数逼近(function approximation).简而言之,从特殊到普通.与此对应的是演绎推理(deductiv ...
 - Ubuntu 安装hadoop 伪分布式
			
一.安装JDK : http://www.cnblogs.com/E-star/p/4437788.html 二.配置SSH免密码登录1.安装所需软件 sudo apt-get ins ...
 - iOS - OC NSProcessInfo		系统进程信息
			
前言 @interface NSProcessInfo : NSObject NSProcessInfo 类中包含一些方法,允许你设置或检索正在运行的应用程序(即进程)的各种类型的信息. 1.获取系统 ...
 - ajax小技巧,防止多次点击发送多个请求
			
var isAjax=false;$("btn").click(function(){ if(isAjax) return; isAjax=true; setTimeout(fun ...