zoukankan      html  css  js  c++  java
  • 多线程中的synchronized小结

    1.synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

    1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
    3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
    4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

    2.synchronized的缺陷

    synchronized是java中的一个关键字,也就是说是Java语言内置的特性。

    如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

    1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;

    2)线程执行发生异常,此时JVM会让线程自动释放锁。

    简单的东西没必要总结,我们来看其中的几个关键点,值得体会,用一个例子说话:

     1 public class Demo4 {
     2     public static void main(String[] args) {
     3         final Output output = new Output();
     4         new Thread(new Runnable() {
     5 
     6             @Override
     7             public void run() {
     8                 while(true){
     9                     try {
    10                         Thread.sleep(500);
    11                     } catch (InterruptedException e) {
    12                         e.printStackTrace();
    13                     }
    14                     output.Output1("chenchi");
    15                 }
    16             }
    17         }).start();
    18 
    19         new Thread(new Runnable() {
    20 
    21             @Override
    22             public void run() {
    23                 while(true){
    24                     try {
    25                         Thread.sleep(500);
    26                     } catch (InterruptedException e) {
    27                         e.printStackTrace();
    28                     }
    29                     output.Output1("sujunjun");
    30                 }
    31             }
    32         }).start();
    33     }
    34 
    35     static class Output {
    36         public void Output1(String name) {
    37             synchronized (this) {
    38                 for (int i = 0; i < name.length(); i++) {
    39                     System.out.print(name.charAt(i));
    40                 }
    41                 System.out.println();
    42             }
    43         }
    44 
    45         public synchronized void Output2(String name) {
    46             for (int i = 0; i < name.length(); i++) {
    47                 System.out.print(name.charAt(i));
    48             }
    49             System.out.println();
    50         }
    51 
    52         public synchronized static void Output3(String name) {
    53             for (int i = 0; i < name.length(); i++) {
    54                 System.out.print(name.charAt(i));
    55             }
    56             System.out.println();
    57         }
    58     }
    59 }

    这个例子很简单,就是同时开启两个线程,声明一个Output内部类的对象,同时访问Output内部类的Output()方法。

    1.

    output.Output1("chenchi");

    output.Output1("sujunjun");

    很明显,打印中不会出现数据错误。synchronized ()只要保证括号里面是同一对象就不会产生错误。里面传的是this,由于两者对象都是output,所以加锁成功。

    想一下,这样会成功吗?(可以)

         String string = "";
            public void Output1(String name) {
                synchronized (string) {
                    for (int i = 0; i < name.length(); i++) {
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }

    这样呢?(可以)

    public void Output1(String name) {
                synchronized ("") {
                    for (int i = 0; i < name.length(); i++) {
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }

    这样呢?(不可以)

    public void Output1(String name) {
                synchronized (name) {
                    for (int i = 0; i < name.length(); i++) {
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }

    2.

    output.Output1("chenchi");

    output.Output2("sujunjun");

    很明显,打印中不会出现错误,因为synchronized修饰方法就是相当于给方法加锁的是当前对象。

    3.

    output.Output1("chenchi");

    output.Output3("sujunjun");

    很明显,打印会出错。为什么呢?还是因为加锁对象不是同一个了。synchronized修饰静态方法后,上锁对象为当前类对象了。

    什么是当前类对象呢?就是Class类型实例,JVM在加载任何一个类时,都会创建一个Class类型的实例描述该类,并且每个类有且只有一个Class的实例描述它。

    如何同步?

    public void Output1(String name) {
                synchronized (Output.class) {
                    for (int i = 0; i < name.length(); i++) {
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }

    这里改了一下Output1方法,Output.class为上锁对象,就保证了同一对象。

  • 相关阅读:
    Delphi-idHttp-JSON用法
    在delphi中, reintroduce作用
    请求转发:MVC设计模式、细节、请求域属性的编程实例、请求重定向和请求转发的区别
    response常见应用、response细节、输出随机图片、定时刷新网页
    HttpServletRequest、request常用方法、request常见应用、请求转发、RequestDispatcher
    Action中取得request,session的四种方式
    List 三种遍历的方法
    java List遍历的方法
    Tag file directory /struts-tags does not start with "/WEB-INF/tags"
    【JavaScript吉光片羽】--- 滑动条
  • 原文地址:https://www.cnblogs.com/DarrenChan/p/5739776.html
Copyright © 2011-2022 走看看