• synchronized常见用法解析及示例


    synchronized作用:
    保证代码执行的原子性;
    保证可见性(与volatile作用相同)

    JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。
    假如再细的分类,synchronized可作用于instance变量、object reference(对象引用,例如this)、static函数和class literals(类名称字面常量)身上。
    下面讨论synchronized用到不同地方对代码产生的影响:

    1.
    对于非static的情况,synchronized是对象级别的,其实质是将synchronized作用于对象引用(object reference)上,即拿到p1对象锁的线程,对p1的fun()方法有同步互斥作用,不同的对象之间坚持“和平共处”。
    假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都能够调用他们。
    (1)把synchronized当作函数修饰符时,示例代码如下:
    public synchronized void method(){
    //….
    }
    这也就是同步方法,那这时synchronized锁定的是哪个对象呢?他锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,他们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却能够任意调用这个被加了synchronized关键字的方法。上边的示例代码等同于如下代码:
    public void method()
    {
    synchronized (this) // (1)
    {
    //…..
    }
    }
    (1)处的this指的是什么呢?他指的就是调用这个方法的对象,如P1。可见,同步方法实质是将synchronized作用于Object Reference。那个拿到了P1对象锁的线程,才能够调用P1的同步方法,而对P2而言,P1这个锁和他毫不相干,代码也可能在这种情形下摆脱同步机制的控制,造成数据混乱,譬如同时操作静态变量时。
    (2).同步块,示例代码如下:
    public void method(SomeObject so) {
    synchronized(so)
    {
    //…..
    }
    }
    这时,锁就是so这个对象,谁拿到这个锁谁就能够运行他所控制的那段代码。当有一个明确的对象作为锁时,就能够这样写代码,但当没有明确的对象作为锁,只是想让一段代码同步时,能够创建一个特别的instance变量(它得是个对象)来充当锁:
    class Foo implements Runnable
    {
    private byte[] lock = new byte[0]; // 特别的instance变量
    Public void method()
    {
    synchronized(lock) { //… }
    }
    //…..
    }
    注:零长度的byte数组对象创建起来将比任何对象都经济。查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
    2.
    如果方法用static修饰,synchronized的作用范围就是class一级的,它对类的所有对象起作用。
    将synchronized作用于static 函数,,示例代码如下:
    Class Foo
    {
    public static synchronized void method1() // 同步的static 函数
    {
    //….
    }
    public void method2()
    {
    synchronized(Foo.class) // class literal(类名称字面常量)
    //请注意,Foo.class也是一个对象,类型是Class,在一个ClassLoader里,它是唯一的。
    }
    }
    代码中的method2()方法是把class literal作为锁的情况,他和同步的static函数产生的效果是相同的,
    取得的锁很特别,是当前调用这个方法的对象所属的类(Class类,而不再是由这个Class产生的某个具体对象了)。

    http://www.strutshome.com/index.php/archives/495

     http://www.2cto.com/kf/201206/134899.html

    http://tech.it168.com/j/2008-01-30/200801302324557.shtml

    1.
    A: synchronized static是某个类的范围,synchronized static cSync{}防止多个线程同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。
    B: synchronized 是某实例的范围,synchronized isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。


    2.
    synchronized方法与synchronized代码快的区别
    synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是 synchronized methods(){} 便于阅读理解,
    而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。

    3.synchronized关键字是不能继承的,即,父类的synchronized方法在子类中不是synchronized,必须要重新的显式的声明为synchronized才行。

    4.实现同步需要很大的系统开销,导致延迟等待,甚至可能造成死锁,所以在非多线程情况下不要使用。

    http://www.cnblogs.com/shipengzhi/articles/2223100.html

    代码示例:

    synchronized使用在方法中是锁住当前对象,此对象中其它synchrinized方法都会阻塞。

    synchronized(this)示例:

    import java.util.concurrent.TimeUnit;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /*2015-4-29*/
    public class SynchronizedTest {
        public static void main(String[] args) throws InterruptedException {
            Task task=new Task(true);
            Thread readThread=new Thread(task, "Reader");
            readThread.start();
            TimeUnit.SECONDS.sleep(2);
            
            task.setRead(false);
            Thread writeThread=new Thread(task, "Writer");
            writeThread.start();
        }
    }
    
    class Task implements Runnable{
        private boolean isRead;
        public Task(boolean isRead) {
            this.isRead=isRead;
        }
        private Logger logger=LoggerFactory.getLogger(Task.class);
        @Override
        public void run() {
            try {
                if (isRead) {
                    read();
                }else {
                    write();
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        public void read() throws InterruptedException{
            synchronized (this) {
                logger.info("Enter read() synchronized");
                TimeUnit.SECONDS.sleep(20);
                logger.info("Ready to leave read()  synchronized");
            }
        }
        
        public void write(){
            logger.info("enter write()");
            synchronized (this) {
                logger.info("enter  write() synchronized");
                logger.info("Ready to leave write() synchronied");
            }
            logger.info("Ready to leave write()");
        }
    
        public void setRead(boolean isRead) {
            this.isRead = isRead;
        }
        
        
    }


    输出:

    [2015-04-30 06:30:21,290] [Reader] INFO - Enter read() synchronized
    [2015-04-30 06:30:23,290] [Writer] INFO - enter write()
    [2015-04-30 06:30:41,290] [Reader] INFO - Ready to leave read()  synchronized
    [2015-04-30 06:30:41,290] [Writer] INFO - enter  write() synchronized
    [2015-04-30 06:30:41,290] [Writer] INFO - Ready to leave write() synchronied
    [2015-04-30 06:30:41,290] [Writer] INFO - Ready to leave write()

    synchronized method_name示例:

    package thread.synchronizedTest;
    
    import java.util.concurrent.TimeUnit;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SynchronizedMethodTest {
        public static void main(String[] args) throws InterruptedException {
            Task3 task3 = new Task3(true);
            Thread readThread = new Thread(task3, "Reader");
            readThread.start();
            TimeUnit.SECONDS.sleep(2);
    
            task3.setRead(false);
            Thread writeThread = new Thread(task3, "Writer");
            writeThread.start();
        }
    }
    
    class Task3 implements Runnable {
        private boolean isRead;
    
        public Task3(boolean isRead) {
            this.isRead = isRead;
        }
    
        private Logger logger = LoggerFactory.getLogger(Task3.class);
    
        @Override
        public void run() {
            try {
                if (isRead) {
                    read();
                } else {
                    write();
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void read() throws InterruptedException {
            logger.info("Enter read() synchronized");
            TimeUnit.SECONDS.sleep(20);
            logger.info("Ready to leave read()  synchronized");
        }
    
        public synchronized void write() {
            logger.info("enter write()");
            // synchronized (this) {
            logger.info("enter  write() synchronized");
            logger.info("Ready to leave write() synchronied");
            // }
            logger.info("Ready to leave write()");
        }
    
        public void setRead(boolean isRead) {
            this.isRead = isRead;
        }
    
    }

    输出:

    [2015-04-30 07:02:04,583] [Reader] INFO - Enter read() synchronized
    [2015-04-30 07:02:24,583] [Reader] INFO - Ready to leave read()  synchronized
    [2015-04-30 07:02:24,583] [Writer] INFO - enter write()
    [2015-04-30 07:02:24,583] [Writer] INFO - enter  write() synchronized
    [2015-04-30 07:02:24,583] [Writer] INFO - Ready to leave write() synchronied
    [2015-04-30 07:02:24,583] [Writer] INFO - Ready to leave write()

    使用一个声明的变量作为锁时,可以让锁的粒度更小,如果合理使用会提高程序执行效率:

    package thread.synchronizedTest;
    
    import java.util.concurrent.TimeUnit;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /*2015-4-29*/
    public class SynchronizedLockObjectTest {
        public static void main(String[] args) throws InterruptedException {
            Task2 task2=new Task2(true);
            Thread readThread=new Thread(task2, "Reader");
            readThread.start();
            TimeUnit.SECONDS.sleep(2);
            
            task2.setRead(false);
            Thread writeThread=new Thread(task2, "Writer");
            writeThread.start();
        }
    }
    
    class Task2 implements Runnable{
        
        private byte[] readLock = new byte[0]; // 特别的instance变量
        private byte[] writeLock = new byte[0]; // 特别的instance变量
    
        
        private boolean isRead;
        public Task2(boolean isRead) {
            this.isRead=isRead;
        }
        private Logger logger=LoggerFactory.getLogger(Task2.class);
        @Override
        public void run() {
            try {
                if (isRead) {
                    read();
                }else {
                    write();
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        public void read() throws InterruptedException{
            synchronized (readLock) {
                logger.info("Enter read() synchronized");
                TimeUnit.SECONDS.sleep(20);
                logger.info("Ready to leave read()  synchronized");
            }
        }
        
        public void write(){
            logger.info("enter write()");
            synchronized (writeLock) {
                logger.info("enter  write() synchronized");
                logger.info("Ready to leave write() synchronied");
            }
            logger.info("Ready to leave write()");
        }
    
        public void setRead(boolean isRead) {
            this.isRead = isRead;
        }
        
        
    }

    输出:

    [2015-04-30 06:37:20,148] [Reader] INFO - Enter read() synchronized
    [2015-04-30 06:37:22,148] [Writer] INFO - enter write()
    [2015-04-30 06:37:22,148] [Writer] INFO - enter  write() synchronized
    [2015-04-30 06:37:22,148] [Writer] INFO - Ready to leave write() synchronied
    [2015-04-30 06:37:22,148] [Writer] INFO - Ready to leave write()
    [2015-04-30 06:37:40,149] [Reader] INFO - Ready to leave read()  synchronized


    synchronized(字段)和synchronized(当前对象)在一个实例中同时存在时,两个方法会同时执行,因为synchronized持有的对象不同,一个是当前对象,一个字段对象:

    package thread.synchronizedTest;
    
    import java.util.concurrent.TimeUnit;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SychronizedLockFieldorMethod {
        public static void main(String[] args) throws InterruptedException {
            Task4 task4 = new Task4(true);
            Thread readThread = new Thread(task4, "Reader");
            readThread.start();
            TimeUnit.SECONDS.sleep(2);
    
            task4.setRead(false);
            Thread writeThread = new Thread(task4, "Writer");
            writeThread.start();
        }
    }
    
    class Task4 implements Runnable {
    
        private byte[] readLock = new byte[0]; // 特别的instance变量
        private byte[] writeLock = new byte[0]; // 特别的instance变量
    
        private boolean isRead;
    
        public Task4(boolean isRead) {
            this.isRead = isRead;
        }
    
        private Logger logger = LoggerFactory.getLogger(Task4.class);
    
        @Override
        public void run() {
            try {
                if (isRead) {
                    read();
                } else {
                    write();
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void read() throws InterruptedException {
            // synchronized (readLock) {
            logger.info("Enter read() synchronized");
            TimeUnit.SECONDS.sleep(20);
            logger.info("Ready to leave read()  synchronized");
            // }
        }
    
        public void write() {
            logger.info("enter write()");
            synchronized (writeLock) {
                logger.info("enter  write() synchronized");
                logger.info("Ready to leave write() synchronied");
            }
            logger.info("Ready to leave write()");
        }
    
        public void setRead(boolean isRead) {
            this.isRead = isRead;
        }
    
    }

    输出:

    [2015-04-30 06:54:41,294] [Reader] INFO - Enter read() synchronized
    [2015-04-30 06:54:43,294] [Writer] INFO - enter write()
    [2015-04-30 06:54:43,294] [Writer] INFO - enter  write() synchronized
    [2015-04-30 06:54:43,294] [Writer] INFO - Ready to leave write() synchronied
    [2015-04-30 06:54:43,294] [Writer] INFO - Ready to leave write()
    [2015-04-30 06:55:01,295] [Reader] INFO - Ready to leave read()  synchronized

    synchronized如果是一个入参,则不能起到同步的作用。因为这种场景和synchronized(this)的原理是一样的。但每次入参都是不同的对象,这些不同的对象不能形成互斥

    import java.util.concurrent.TimeUnit;
    
    public class SynchronizedParameter implements Runnable {
        private static Biz biz = new Biz();
    
        private String key;
    
        public SynchronizedParameter(String key) {
            this.key = key;
        }
    
        public static void main(String[] args) throws InterruptedException {
    
            String key1 = "key1";
            Thread thread1 = new Thread(new SynchronizedParameter(key1), key1);
            String key2 = "key2";
            Thread thread2 = new Thread(new SynchronizedParameter(key2), key2);
            Thread thread2_bak = new Thread(new SynchronizedParameter(key2), key2 + "bak");
    
            thread1.start();
            thread2.start();
            thread2_bak.start();
    
            thread1.join();
            thread2.join();
            thread2_bak.join();
    
            System.out.println(Thread.currentThread() + "end...");
        }
    
    
        @Override
        public void run() {
            biz.handle(key);
        }
    
        public void setKey(String key) {
            this.key = key;
        }
    
    
    }
    
    class Biz {
    
    
        public void handle(String key) {
            System.out.println(Thread.currentThread() + " " + key + " " + System.currentTimeMillis());
            synchronized (key) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread() + " " + key + " " + System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
    }
    Thread[key1,5,main] key1 1476842469690
    Thread[key2,5,main] key2 1476842469691
    Thread[key2bak,5,main] key2 1476842469695
    Thread[key2,5,main] key2 1476842470691
    Thread[key1,5,main] key1 1476842470691
    Thread[key2bak,5,main] key2 1476842471691
    Thread[main,5,main]end...



  • 相关阅读:
    linux两数相除计算百分数
    安装lombok
    STS(spring tool suite)修改默认编码
    eclipse项目中的java文件导入后变为空心J问题
    说Gradle
    window下安装git与git使用
    windows下安装git
    Javaweb 实现分页功能
    Xshell连接不上Ubuntu解决方式
    ubuntu下中文乱码解决
  • 原文地址:https://www.cnblogs.com/softidea/p/4034164.html
Copyright © 2020-2023  润新知