同步方法和同步块

同步方法和同步块(synchronized)

一、 同步方法

1. public synchronized void method(){}

synchronized方法控制对 “对象” 的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象锁才能执行。否则会导致阻塞。方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。

2. 若将一个大方法申明为一个synchronized方法,将极大的影响效率。

二、同步块

1. synchronized(Obj){}

  • Obj(同步监视器)可以是任何对象,但推荐使用共享资源作为同步监视器。

  • 同步方法中无需指定同步监视器,因为同步方法中的同步监视器就是this,就是这个对象本身,也可以是class。

2. 同步块的Obj就是被修改的对象,方法体的内容为:对这个对象的增删改

三、使用同步方法和同步块对三个不安全实例的优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//对于不安全的买票机制,只需要对Buytickets中的buy方法加上synchronized修饰。因为变量ticketNum就是本类中的属性,buy方法也对ticketNum进行修改。
package demo.study.syn;

public class UnsafeBuyTickets {
public static void main(String[] args) {
Buytickets station = new Buytickets();
new Thread(station,"小明").start();
new Thread(station,"小红").start();
new Thread(station,"黄牛").start();
}

}

class Buytickets implements Runnable{
private int ticketNum = 10;
boolean flag = true;
@Override
public void run() {
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//只需用synchronized对buy方法修饰
public synchronized void buy() throws InterruptedException {
if (this.ticketNum<=0){
flag = false;
return ;
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"买到了"+ticketNum--);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//对于不安全的银行机制,不能只是将run方法加个synchronized修饰,因为,run方法的对象是整个Drawing,对Drawing上锁不足以解决资源共享问题。而是使用同步块对account对象进行追踪,并把对account操作的语句添加到方法体中。
package demo.study.syn;
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(1000,"中国银行");
Drawing you = new Drawing(account,50,"you");
Drawing girlFriend = new Drawing(account,100,"girlFriend");
you.start();
girlFriend.start();
}
}
class Account{
int money;
String name;

public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
class Drawing extends Thread{
Account account;
int drawMoney;
int nowMoney;
String name;
public Drawing(Account account,int drawMoney,String name){
super(name);
this.account=account;
this.drawMoney=drawMoney;
}

@Override
public void run() {
synchronized (account){
if (account.money-drawMoney<0) {
System.out.println(Thread.currentThread().getName()+"钱不够了");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawMoney;
nowMoney+=drawMoney;
System.out.println(Thread.currentThread().getName()+"手里的钱"+nowMoney);
System.out.println(account.name+"卡内余额"+account.money);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 对不安全的list的优化
package demo.study.syn;

import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list) {
list.add(Thread.currentThread().getName());
}
}).start();
}
System.out.println(list.size());
}
}

-------------本文结束感谢您的阅读-------------