多线程中的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为上锁对象,就保证了同一对象。

原文地址:https://www.cnblogs.com/DarrenChan/p/5739776.html