synchronized关键字小结(一)

1. synchronized同步方法

1) synchronized修饰方法,表示方法是同步的,当某线程进入并拿到当前整个对象的锁时

a. 其他synchronized方法排队等锁

b. 非synchronized方法可异步执行

示例代码(折叠)

 1 package com.khlin.thread;
 2
 3 public class SynchronizedTest {
 4
 5     public static void main(String[] args) {
 6         Service service = new Service();
 7         /**
 8          * A B 两个方法是同步的,因此访问A时候,要等A方法执行完,A线程释放锁,B线程才能拿到锁从而访问B方法。
 9          * 而C方法并不是同步的,可以异步执行
10          */
11         ThreadA threadA = new ThreadA(service);
12         threadA.start();
13
14         ThreadB threadB = new ThreadB(service);
15         threadB.start();
16
17         ThreadC threadC = new ThreadC(service);
18         threadC.start();
19     }
20 }
21
22 class ThreadA extends Thread {
23
24     private Service service;
25
26     public ThreadA(Service service) {
27         this.service = service;
28     }
29
30     public void run() {
31         super.run();
32         service.printA();
33     }
34 }
35
36 class ThreadB extends Thread {
37
38     private Service service;
39
40     public ThreadB(Service service) {
41         this.service = service;
42     }
43
44     public void run() {
45         super.run();
46         service.printB();
47     }
48 }
49
50 class ThreadC extends Thread {
51
52     private Service service;
53
54     public ThreadC(Service service) {
55         this.service = service;
56     }
57
58     public void run() {
59         super.run();
60         service.printC();
61     }
62 }
63
64 class Service {
65     public synchronized void printA() {
66
67         System.out.println("enter printA. thread name: "
68                 + Thread.currentThread().getName());
69
70         try {
71             Thread.sleep(3000L);
72         } catch (InterruptedException e) {
73             // TODO Auto-generated catch block
74             e.printStackTrace();
75         }
76
77         System.out.println("leaving printA. thread name: "
78                 + Thread.currentThread().getName());
79     }
80
81     public synchronized void printB() {
82
83         System.out.println("enter printB. thread name: "
84                 + Thread.currentThread().getName());
85
86         System.out.println("leaving printB. thread name: "
87                 + Thread.currentThread().getName());
88     }
89
90     public void printC() {
91
92         System.out.println("enter printC. thread name: "
93                 + Thread.currentThread().getName());
94
95         System.out.println("leaving printC. thread name: "
96                 + Thread.currentThread().getName());
97     }
98 }

synchronized方法

运行结果:

2) 拥有锁重入的功能,当一个线程获得一个对象锁之后 ,再次请求此对象锁的时候是可以再次获得的。

示例代码,修改上面示例代码,在A方法后面调用B方法,可以再次获得锁,运行结果:

3) 重写方法后,synchronized关键字并不继承。但没有被重写的方法,仍然是同步的。

  1 package com.khlin.thread;
  2
  3 public class SynchronizedTest {
  4
  5     public static void main(String[] args) {
  6         /**
  7          * 子类方法的实现若调用了父类的同步方法,一样有效
  8          */
  9         SubService service = new SubService();
 10         /**
 11          * A B 两个方法是同步的,因此访问A时候,要等A方法执行完,A线程释放锁,B线程才能拿到锁从而访问B方法。
 12          * 而C方法并不是同步的,可以异步执行
 13          */
 14         ThreadA threadA = new ThreadA(service);
 15         threadA.setName("threadA");
 16         threadA.start();
 17
 18         ThreadB threadB = new ThreadB(service);
 19         threadB.setName("threadB");
 20         threadB.start();
 21
 22         ThreadC threadC = new ThreadC(service);
 23         threadC.setName("threadC");
 24         threadC.start();
 25     }
 26 }
 27
 28 class ThreadA extends Thread {
 29
 30     private Service service;
 31
 32     public ThreadA(Service service) {
 33         this.service = service;
 34     }
 35
 36     public void run() {
 37         super.run();
 38         service.printA();
 39         // service.printB();
 40     }
 41 }
 42
 43 class ThreadB extends Thread {
 44
 45     private Service service;
 46
 47     public ThreadB(Service service) {
 48         this.service = service;
 49     }
 50
 51     public void run() {
 52         super.run();
 53         service.printB();
 54     }
 55 }
 56
 57 class ThreadC extends Thread {
 58
 59     private Service service;
 60
 61     public ThreadC(Service service) {
 62         this.service = service;
 63     }
 64
 65     public void run() {
 66         super.run();
 67         service.printC();
 68     }
 69 }
 70
 71 class Service {
 72     public synchronized void printA() {
 73
 74         System.out.println("enter printA. thread name: "
 75                 + Thread.currentThread().getName());
 76
 77         try {
 78             Thread.sleep(3000L);
 79         } catch (InterruptedException e) {
 80             // TODO Auto-generated catch block
 81             e.printStackTrace();
 82         }
 83
 84         System.out.println("leaving printA. thread name: "
 85                 + Thread.currentThread().getName());
 86
 87         // printB();
 88     }
 89
 90     public synchronized void printB() {
 91
 92         System.out.println("enter printB. thread name: "
 93                 + Thread.currentThread().getName());
 94
 95         System.out.println("leaving printB. thread name: "
 96                 + Thread.currentThread().getName());
 97     }
 98
 99     public void printC() {
100
101         System.out.println("enter printC. thread name: "
102                 + Thread.currentThread().getName());
103
104         System.out.println("leaving printC. thread name: "
105                 + Thread.currentThread().getName());
106     }
107 }
108
109 class SubService extends Service {
110
111     public void printSubA() {
112         System.out.println("enter printSubA. thread name: "
113                 + Thread.currentThread().getName());
114         printA();
115         System.out.println("leaving printSubA. thread name: "
116                 + Thread.currentThread().getName());
117     }
118 }

运行结果和1)是一样的。

2. synchronized同步代码块

同步代码块,通过synchronized(一个对象)的写法,把一个代码块变成同步的。

其中,括号里待同步的对象,也可以使用this关键字,指向当前对象,这时与synchronized方法效果是一样的。

1) 被同步的对象是this的情况

与synchronized方法效果一样,示例代码:

 1 package com.khlin.thread;
 2
 3 public class SynchronizedTestSecond {
 4
 5     public static void main(String[] args) {
 6         ServiceSecond service = new ServiceSecond();
 7
 8         ThreadAA threadAA = new ThreadAA(service);
 9         threadAA.setName("ThreadAA");
10         threadAA.start();
11
12         try {
13             Thread.sleep(500L);
14         } catch (InterruptedException e) {
15             // TODO Auto-generated catch block
16             e.printStackTrace();
17         }
18
19         ThreadBB threadBB = new ThreadBB(service);
20         threadBB.setName("ThreadBB");
21         threadBB.start();
22     }
23
24 }
25
26 class ServiceSecond {
27
28     public void methodA() {
29         String threadName = Thread.currentThread().getName();
30         synchronized (this) {
31             System.out.println("invoke methodA. " + threadName);
32             try {
33                 Thread.sleep(1000L);
34             } catch (InterruptedException e) {
35                 // TODO Auto-generated catch block
36                 e.printStackTrace();
37             }
38             System.out.println("finish invoking methodA. " + threadName);
39         }
40     }
41
42     public synchronized void methodB() {
43         String threadName = Thread.currentThread().getName();
44         System.out.println("invoke methodB. " + threadName);
45         System.out.println("finish invoking methodA. " + threadName);
46     }
47 }
48
49 class ThreadAA extends Thread {
50     ServiceSecond service = new ServiceSecond();
51
52     public ThreadAA(ServiceSecond service) {
53         this.service = service;
54     }
55     public void run() {
56         service.methodA();
57     }
58 }
59
60 class ThreadBB extends Thread {
61     ServiceSecond service = new ServiceSecond();
62
63     public ThreadBB(ServiceSecond service) {
64         this.service = service;
65     }
66     public void run() {
67         service.methodB();
68     }
69 }

运行结果:

2) 被同步的对象非this的情况

假设synchronized(x),此时,访问x对象里的同步方法,是同步访问的。

而访问主对象的同步方法,不受同步影响,属于异步。

让我们把上面的代码改为,synchronized(operation),锁住另一个对象。

 1 package com.khlin.thread;
 2
 3 public class SynchronizedTestSecond {
 4
 5     public static void main(String[] args) {
 6         ServiceSecond service = new ServiceSecond();
 7
 8         /**
 9          * 锁住了operation对象,该对象的同步方法必须等待锁
10          * 而methodB并不属于该对象,ServiceSecond对象的锁,其实线程AA并没有获取,所以线程BB可以异步访问methodB方法。
11          */
12
13         ThreadAA threadAA = new ThreadAA(service);
14         threadAA.setName("ThreadAA");
15         threadAA.start();
16
17         try {
18             Thread.sleep(500L);
19         } catch (InterruptedException e) {
20             // TODO Auto-generated catch block
21             e.printStackTrace();
22         }
23
24         ThreadBB threadBB = new ThreadBB(service);
25         threadBB.setName("ThreadBB");
26         threadBB.start();
27     }
28
29 }
30
31 class ServiceSecond {
32
33     private ServiceOperation operation = new ServiceOperation();
34
35     public void methodA() {
36         String threadName = Thread.currentThread().getName();
37
38         synchronized (operation) {
39             System.out.println("invoke methodA. " + threadName);
40             try {
41                 Thread.sleep(1000L);
42             } catch (InterruptedException e) {
43                 // TODO Auto-generated catch block
44                 e.printStackTrace();
45             }
46             System.out.println("finish invoking methodA. " + threadName);
47         }
48     }
49
50     public synchronized void methodB() {
51         String threadName = Thread.currentThread().getName();
52         System.out.println("invoke methodB. " + threadName);
53         System.out.println("finish invoking methodB. " + threadName);
54     }
55 }
56
57 class ServiceOperation {
58
59     public synchronized void methodOperation() {
60         System.out.println("this is operation method.");
61     }
62 }
63
64 class ThreadAA extends Thread {
65     ServiceSecond service = new ServiceSecond();
66
67     public ThreadAA(ServiceSecond service) {
68         this.service = service;
69     }
70     public void run() {
71         service.methodA();
72     }
73 }
74
75 class ThreadBB extends Thread {
76     ServiceSecond service = new ServiceSecond();
77
78     public ThreadBB(ServiceSecond service) {
79         this.service = service;
80     }
81     public void run() {
82         service.methodB();
83     }
84 }

运行结果:

因为线程BB在访问methodB的时候,service对象的锁并没有被占用着,所以可以直接占用并调用方法。

3. 静态方法的synchronized方法和synchronized(class)方法

这是对类加锁,注意,在java中,类是一种特殊的对象。

原理与上述的非静态方法同步是一样的,不再赘述。

示例代码:

 1 package com.khlin.thread;
 2
 3 public class SynchronizedStatic {
 4
 5     public static void main(String[] args) {
 6         ThreadAAA threadAAA = new ThreadAAA();
 7         threadAAA.setName("ThreadAAA");
 8         threadAAA.start();
 9
10         try {
11             Thread.sleep(500L);
12         } catch (InterruptedException e) {
13             // TODO Auto-generated catch block
14             e.printStackTrace();
15         }
16
17         ThreadBBB threadBBB = new ThreadBBB();
18         threadBBB.setName("ThreadBBB");
19         threadBBB.start();
20     }
21 }
22
23 class StaticService {
24     public synchronized static void methodA()
25     {
26         String threadname = Thread.currentThread().getName();
27
28         System.out.println("invoking methodA. " + threadname);
29
30         try {
31             Thread.sleep(1000L);
32         } catch (InterruptedException e) {
33             // TODO Auto-generated catch block
34             e.printStackTrace();
35         }
36
37         System.out.println("finish methodA. " + threadname);
38     }
39
40     public synchronized static void methodB()
41     {
42         String threadname = Thread.currentThread().getName();
43
44         System.out.println("invoking methodB. " + threadname);
45
46         System.out.println("finish methodB. " + threadname);
47     }
48 }
49
50 class ThreadAAA extends Thread {
51
52
53     public void run() {
54         StaticService.methodA();
55     }
56 }
57
58 class ThreadBBB extends Thread {
59
60
61     public void run() {
62         StaticService.methodB();
63     }
64 }

运行结果:

时间: 2024-10-18 14:03:09

synchronized关键字小结(一)的相关文章

关于Java中的synchronized关键字

[内容简介] 本文主要介绍Java中如何正确的使用synchronized关键字实现线程的互斥锁. [能力需求] 至少已经完整的掌握了Java的语法基础,基本的面向对象知识,及创建并启动线程. [正文] 关于synchronized关键字的使用,很多说法是“锁同一个对象”就可以确保锁是正常的,今天,有人提了一个问题,我觉得非常不错,所以与各位一起分享一下. 在这里,就不提关于线程和synchronized关键字的基本使用了,以非常传统的“银行取钱”的故事为案例,直接上代码:Ps:以下代码是直接敲

synchronized关键字以及实例锁 类锁

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 二.然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块.

JAVA线程安全之synchronized关键字的正确用法

JAVA线程安全关于synchronized关键字的用法,今天才知道原来我一直错了.以为用了synchronized关键字包住了代码就可以线程同步安全了. 测试了下.发现是完全的错了.synchronized必须正确的使用才是真正的线程安全...虽然知道这种写法,一直以为却由于懒而用了错误的方法. 看来基础还没有打好.仍需复习加强!工作中犯这种错误是不可原谅的,要知道使用synchronized关键字的地方都是数据敏感的!汗一把... 先贴代码: [java] view plaincopypri

java中的synchronized关键字

参考:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html 多线程问题的根因: 多线程环境下,对一个对象更改的时候,一个线程A对某个变量做了改变,但是还没改变完成能,就被另外一个线程B抢去了cpu,那么A就不会再执行了,因此导致了数据不一致行为.针对上面引文中银行取款存款的例子,本来存一百取一百正好抵消,但是由于多线程的之间的肆意抢占,有些取存款的操作没有完成,自然导致结果千奇百怪. 关键点: synchronized

java基础回顾(五)线程详解以及synchronized关键字

本文将从线程的使用方式.源码.synchronized关键字的使用方式和陷阱以及一些例子展开java线程和synchronized关键字的内容. 一.线程的概念 线程就是程序中单独顺序的流控制.线程本 身不能运行,它只能用于程序中. 二.线程的实现 线程的实现有两种方式: 1.继承Thread类并重写run方法 2.通过定义实现Runnable接口的类进而实现run方法 当用第一种方式时我们需要重写run方法因为Thread类里的run方法什么也不做(见下边的源码),当用第二种方式时我们需要实现

java synchronized关键字浅探

synchronized 是 java 多线程编程中用于使线程之间的操作串行化的关键字.这种措施类似于数据库中使用排他锁实现并发控制,但是有所不同的是,数据库中是对数据对象加锁,而 java 则是对将要执行的代码加锁. 在 java 中使用 synchronized 关键字时需要注意以下几点: 1.synchronized 是针对同一个资源的访问作出限制.这是出现该关键字的原因. 2.对于类而言,某一个线程执行到一个 synchronized 修饰的类方法或者类方法中的代码段时,该方法或者代码段

java synchronized关键字

Java中synchronized关键字和对象的内置锁结合使用,用来保护代码块在并发环境下的线程安全,可以使被保护的代码块操作原子性. synchronized关键字可以用于修饰方法来保护方法内的全部代码块,可以用synchronized(对象1) 的方式保护指定代码块.(这里说一下:很多书中都说synchronized可以给对象加锁,我实在不愿意这么说,这样让我概念混淆...因为,对象内置锁是本来就存在的,不是谁加给它的,"synchronized(对象1)"我更愿意解释成:执行到此

Java 并发编程中使用 ReentrantLock 替代 synchronized 关键字原语

Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能.使用方法也很简单: public final ReentrantLock lock=new ReentrantLock(); ...... try { lock.lock(); // 进入同步内容 .... } finally { lock.unlock(); // 必须在 finally 块中解锁,否

java的线程同步机制synchronized关键字的理解

线程同步:               由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 需要明确的几个问题: 1)synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块.如果 再细的分类,synchronized可作用于instance变量.object reference(对象引用).static函数和clas