synchronize——对象锁和类锁

最近在研究Java 多线程的只是,经常能看到synchronize关键字,以前只是一眼带过,没有细究,今天趁这个机会,整理下

synchronize作为多线程关键字,是一种同步锁,它可以修饰以下几种对象:

代码块:被修饰的代码块称为同步语句块,其作用的范围是大括号{ }里的代码,作用的对象是调用这个代码块的对象;

方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象

静态方法:作用的范围是整个静态方法,作用的对象是这个类的所有对象

类:作用的范围是synchronize后面括号里的部分,作用的对象是这个类的所有对象

一、synchronize关键字

1.修饰方法

1 synchronized public void getValue() {
2     System.out.println("getValue method thread name="
3             + Thread.currentThread().getName() + " username=" + username
4             + " password=" + password);
5 }

2.修饰代码块

 1 public void serviceMethod() {
 2     try {
 3         synchronized (this) {
 4             System.out.println("begin time=" + System.currentTimeMillis());
 5             Thread.sleep(2000);
 6             System.out.println("end    end=" + System.currentTimeMillis());
 7         }
 8     } catch (InterruptedException e) {
 9         e.printStackTrace();
10     }
11 }

3.修饰类

 1 public static void printA() {
 2         synchronized (Service.class) {
 3             try {
 4                 System.out.println("线程名称为:" + Thread.currentThread().getName()
 5                         + "在" + System.currentTimeMillis() + "进入printA");
 6                 Thread.sleep(3000);
 7                 System.out.println("线程名称为:" + Thread.currentThread().getName()
 8                         + "在" + System.currentTimeMillis() + "离开printA");
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12         }
13
14     }

二、Java中的对象锁和类锁

借用网友对对象锁和类锁定义

1 一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
2 在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
3 如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。
4 取到锁后,他就开始执行同步代码(被synchronized修饰的代码);
5 线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
6 这样就保证了同步代码在统一时刻只有一个线程在执行。

三、synchronize的用法与实例

总结:

synchronize修饰非静态方法、同步代码块的synchronize(this)和synchronize(非this对象)的用法锁的是对象,线程想要执行对应的同步代码,需要获得对象锁。

synchronize修饰静态方法以及同步代码块的synchronize(类.class)用法锁是类,线程想要执行对应的同步代码,需要获得类锁。

1.首先看下非线程安全例子

 1 public class Run {
 2
 3     public static void main(String[] args) {
 4
 5         HasSelfPrivateNum numRef = new HasSelfPrivateNum();
 6
 7         ThreadA athread = new ThreadA(numRef);
 8         athread.start();
 9
10         ThreadB bthread = new ThreadB(numRef);
11         bthread.start();
12
13     }
14
15 }
16
17 class HasSelfPrivateNum {
18
19     private int num = 0;
20
21     public void addI(String username) {
22         try {
23             if (username.equals("a")) {
24                 num = 100;
25                 System.out.println("a set over!");
26                 Thread.sleep(2000);
27             } else {
28                 num = 200;
29                 System.out.println("b set over!");
30             }
31             System.out.println(username + " num=" + num);
32         } catch (InterruptedException e) {
33             // TODO Auto-generated catch block
34             e.printStackTrace();
35         }
36     }
37
38 }
39
40
41 class ThreadA extends Thread {
42
43     private HasSelfPrivateNum numRef;
44
45     public ThreadA(HasSelfPrivateNum numRef) {
46         super();
47         this.numRef = numRef;
48     }
49
50     @Override
51     public void run() {
52         super.run();
53         numRef.addI("a");
54     }
55
56 }
57
58
59
60  class ThreadB extends Thread {
61
62     private HasSelfPrivateNum numRef;
63
64     public ThreadB(HasSelfPrivateNum numRef) {
65         super();
66         this.numRef = numRef;
67     }
68
69     @Override
70     public void run() {
71         super.run();
72         numRef.addI("b");
73     }
74
75 }

运行结果:

1 a set over!
2 b set over!
3 b num=200
4 a num=200

修改HasSelfPrivateNum如下,方法用synchronize修饰如下:

 1 class HasSelfPrivateNum {
 2
 3     private int num = 0;
 4
 5     synchronized public void addI(String username) {
 6         try {
 7             if (username.equals("a")) {
 8                 num = 100;
 9                 System.out.println("a set over!");
10                 Thread.sleep(2000);
11             } else {
12                 num = 200;
13                 System.out.println("b set over!");
14             }
15             System.out.println(username + " num=" + num);
16         } catch (InterruptedException e) {
17             // TODO Auto-generated catch block
18             e.printStackTrace();
19         }
20     }
21
22 }

运行结果是线程安全的:

1 b set over!
2 b num=200
3 a set over!
4 a num=100

由于sleep方法不会放弃对象锁,需要等到时间结束,释放锁,下一个进程才能获取到该对象锁

实验结论:两个线程访问同一个对象中的同步方法是一定是线程安全的。本实现由于是同步访问,所以先打印出a,然后打印出b。

这里线程获取的是HasSelfPrivateNum的对象实例的锁——对象锁。

2.多个对象多个锁

 1 public class Run {
 2
 3     public static void main(String[] args) {
 4
 5         HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
 6         HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
 7
 8         ThreadA athread = new ThreadA(numRef1);
 9         athread.start();
10
11         ThreadB bthread = new ThreadB(numRef2);
12         bthread.start();
13
14     }
15
16 }

运行结果:

1 a set over!
2 b set over!
3 b num=200
4 a num=200

这里是非同步的,因为线程athread获得是numRef1的对象锁,而bthread线程获取的是numRef2的对象锁,他们并没有在获取锁上有竞争关系,因此,出现非同步的结果。

3.同步块synchronize(this)

 1 public class Run {
 2
 3     public static void main(String[] args) {
 4         ObjectService service = new ObjectService();
 5
 6         ThreadA a = new ThreadA(service);
 7         a.setName("a");
 8         a.start();
 9
10         ThreadB b = new ThreadB(service);
11         b.setName("b");
12         b.start();
13     }
14
15 }
16
17 class ObjectService {
18
19     public void serviceMethod() {
20         try {
21             synchronized (this) {
22                 System.out.println("begin time=" + System.currentTimeMillis());
23                 Thread.sleep(2000);
24                 System.out.println("end    end=" + System.currentTimeMillis());
25             }
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29     }
30 }
31
32
33 class ThreadA extends Thread {
34
35     private ObjectService service;
36
37     public ThreadA(ObjectService service) {
38         super();
39         this.service = service;
40     }
41
42     @Override
43     public void run() {
44         super.run();
45         service.serviceMethod();
46     }
47
48 }
49
50
51 class ThreadB extends Thread {
52     private ObjectService service;
53
54     public ThreadB(ObjectService service) {
55         super();
56         this.service = service;
57     }
58
59     @Override
60     public void run() {
61         super.run();
62         service.serviceMethod();
63     }
64 }

运行结果:

1 begin time=1466148260341
2 end    end=1466148262342
3 begin time=1466148262342
4 end    end=1466148264378

这样也是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是ObjectService实例对象的对象锁了。

4.synchronize(非this对象)

 1 public class Run {
 2
 3     public static void main(String[] args) {
 4
 5         Service service = new Service("xiaobaoge");
 6
 7         ThreadA a = new ThreadA(service);
 8         a.setName("A");
 9         a.start();
10
11         ThreadB b = new ThreadB(service);
12         b.setName("B");
13         b.start();
14
15     }
16
17 }
18
19 class Service {
20
21     String anyString = new String();
22
23     public Service(String anyString){
24         this.anyString = anyString;
25     }
26
27     public void setUsernamePassword(String username, String password) {
28         try {
29             synchronized (anyString) {
30                 System.out.println("线程名称为:" + Thread.currentThread().getName()
31                         + "在" + System.currentTimeMillis() + "进入同步块");
32                 Thread.sleep(3000);
33                 System.out.println("线程名称为:" + Thread.currentThread().getName()
34                         + "在" + System.currentTimeMillis() + "离开同步块");
35             }
36         } catch (InterruptedException e) {
37             // TODO Auto-generated catch block
38             e.printStackTrace();
39         }
40     }
41
42 }
43
44 class ThreadA extends Thread {
45     private Service service;
46
47     public ThreadA(Service service) {
48         super();
49         this.service = service;
50     }
51
52     @Override
53     public void run() {
54         service.setUsernamePassword("a", "aa");
55
56     }
57
58 }
59
60
61 class ThreadB extends Thread {
62
63     private Service service;
64
65     public ThreadB(Service service) {
66         super();
67         this.service = service;
68     }
69
70     @Override
71     public void run() {
72         service.setUsernamePassword("b", "bb");
73
74     }
75
76 }

不难看出,这里线程争夺的是anyString的对象锁,两个线程有竞争同一对象锁的关系,出现同步。

5.静态synchronize同步方法

 1 public class Run {
 2
 3     public static void main(String[] args) {
 4
 5         ThreadA a = new ThreadA();
 6         a.setName("A");
 7         a.start();
 8
 9         ThreadB b = new ThreadB();
10         b.setName("B");
11         b.start();
12
13     }
14
15 }
16
17 class Service {
18
19     synchronized public static void printA() {
20         try {
21             System.out.println("线程名称为:" + Thread.currentThread().getName()
22                     + "在" + System.currentTimeMillis() + "进入printA");
23             Thread.sleep(3000);
24             System.out.println("线程名称为:" + Thread.currentThread().getName()
25                     + "在" + System.currentTimeMillis() + "离开printA");
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29     }
30
31     synchronized public static void printB() {
32         System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
33                 + System.currentTimeMillis() + "进入printB");
34         System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
35                 + System.currentTimeMillis() + "离开printB");
36     }
37
38 }
39
40
41 class ThreadA extends Thread {
42     @Override
43     public void run() {
44         Service.printA();
45     }
46
47 }
48
49
50 class ThreadB extends Thread {
51     @Override
52     public void run() {
53         Service.printB();
54     }
55 }

运行结果:

1 线程名称为:A在1466149372909进入printA
2 线程名称为:A在1466149375920离开printA
3 线程名称为:B在1466149375920进入printB
4 线程名称为:B在1466149375920离开printB

两个线程在争夺同一个类锁,因此同步。

6.synchronize(class)

 1 class Service {
 2
 3     public static void printA() {
 4         synchronized (Service.class) {
 5             try {
 6                 System.out.println("线程名称为:" + Thread.currentThread().getName()
 7                         + "在" + System.currentTimeMillis() + "进入printA");
 8                 Thread.sleep(3000);
 9                 System.out.println("线程名称为:" + Thread.currentThread().getName()
10                         + "在" + System.currentTimeMillis() + "离开printA");
11             } catch (InterruptedException e) {
12                 e.printStackTrace();
13             }
14         }
15
16     }
17
18     public static void printB() {
19         synchronized (Service.class) {
20             System.out.println("线程名称为:" + Thread.currentThread().getName()
21                     + "在" + System.currentTimeMillis() + "进入printB");
22             System.out.println("线程名称为:" + Thread.currentThread().getName()
23                     + "在" + System.currentTimeMillis() + "离开printB");
24         }
25     }
26 }

运行结果:

1 线程名称为:A在1466149372909进入printA
2 线程名称为:A在1466149375920离开printA
3 线程名称为:B在1466149375920进入printB
4 线程名称为:B在1466149375920离开printB

两个线程依旧在争夺同一个类锁,因此同步。

原文地址:https://www.cnblogs.com/zyxiaohuihui/p/9096882.html

时间: 2024-11-05 18:44:12

synchronize——对象锁和类锁的相关文章

Java学习(十一):Java锁Synchronized,对象锁和类锁举例

Java的锁分为对象锁和类锁. 1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内针对该对象的操作只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 2. 然而,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块. 3. 尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对该object中所有其它sync

从头认识多线程-2.2 synchronized持有对象锁与类锁的相同点

这一章节我们来讨论一下synchronized持有对象锁与类锁的相同点. 1.当所有方法都不使用同步的时候 代码清单 package com.ray.deepintothread.ch02.topic_2; public class SynchInstance1 { public static void main(String[] args) throws InterruptedException { MyTestObjectOne myTestObjectOne = new MyTestObj

【Thread】java线程之对象锁、类锁、线程安全

说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来了. 一.基本说明 类.对象:...(不知道怎么说,只可意会不可言传>.<!):要明白哪些方法.变量是对象的,哪些是类的. 类锁.对象锁:对应类和对象.每个类有且仅有一个类锁,每个对象有且仅有一个对象锁. ex: Person p1 = new Person(); Person p2 = new

从头认识多线程-2.3 synchronized持有对象锁与类锁的不同点

这一章节我们来讨论游戏,synchronized持有对象锁与类锁的不同点-两种锁是并行的东西,没有交集. 1.同步持有对象锁或者类锁 package com.ray.deepintothread.ch02.topic_3; public class SynchInstance5 { public static void main(String[] args) throws InterruptedException { MyTestObjectFive myTestObjectFive = new

java 对象锁和类锁的区别(转)

java 对象锁和类锁的区别   转自 <http://zhh9106.iteye.com/blog/2151791> 在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途

Java对象锁和类锁全面解析(多线程synchronized关键字)

最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念.最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没用对都不知道. 今天把一些疑惑都解开了,写篇文章分享给大家,文章还算比较全面.当然可能有小宝鸽理解得不够深入透彻的地方,如果说得不正确还望指出. 看之前有必要跟某些猿友说一下,如果看一遍没有看明白呢,也没关系,当是了解一下,等真正使用到了,再回头看. 本文主要是将synchronized关键字用法作

java的同步方法和同步代码块,对象锁,类锁区别

/** * @author admin * @date 2018/1/12 9:48 * 作用在同一个实例对象上讨论 * synchronized同步方法的测试 * 两个线程,一个线程调用synchronized修饰方法,另一个线程可以调用非synchronized修饰的方法,互不影响 */ public class SynchronizedTest { public synchronized void methodA() { try { for (int i = 0; i < 5; i++)

synchronized关键字以及对象锁和类锁的区别

java并发编程中最长用到的关键字就是synchronized了,这里讲解一下这个关键字的用法和容易混淆的地方.synchronized关键字涉及到锁的概念, 在java中,synchronized锁大家又通俗的称为:方法锁,对象锁 和 类锁 三种. 先上结论! 1 无论是修饰方法还是修饰代码块都是 对象锁,当一个线程访问一个带synchronized方法时,由于对象锁的存在,所有加synchronized的方法都不能被访问(前提是在多个线程调用的是同一个对象实例中的方法)2 无论是修饰静态方法

zbb20180929 thread 自旋锁、阻塞锁、可重入锁、悲观锁、乐观锁、读写锁、对象锁和类锁

1.自旋锁自旋锁可以使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得锁,则继续执行.若线程依然不能获得锁,才会被挂起.使用自旋锁后,线程被挂起的几率相对减少,线程执行的连贯性相对加强.因此,对于那些锁竞争不是很激烈,锁占用时间很短的并发线程,具有一定的积极意义,但对于锁竞争激烈,单线程锁占用很长时间的并发程序,自旋锁在自旋等待后,往往毅然无法获得对应的锁,不仅仅白白浪费了CPU时间,最终还是免不了被挂起的操作 ,