您的位置:首页 > 编程语言 > Java开发

Java并发编程-06-Synchronize关键字同步机制

2015-06-14 20:06 609 查看
一、临界区 Critical Section

临界区是一个用以访问共享资源的代码块,这个代码块在同一时间内只允许一个线程执行

二、同步

1、当一个线程试图访问一个临界资源时,它将使用一种同步机制来查看是不是已经有其他的线程进入临界区

2、如果临界区没有其他线程,它就可以进入临界区。如果已经有线程进入临界区,它就被同步机制挂起,直到进入的线程离开这个临界区

3、如果在等待进入临界区的线程不止一个,jvm就会选择其中一个,其他的继续等待

三、java采用的两种基本的同步机制

synchronized关键字机制

Lock接口及其实现

四、synchronize关键字机制

synchronize修饰方法

1、使用synchronize关键字的方法性能比较低

2、每一个使用synchronize修饰的方法都是临界区

3、使用synchronize修饰的对象,那么同一时间只能有一个执行线程访问,如果其他线程试图访问这个对象的其他方法,都将被挂起

4、synchronize修饰静态方法会怎么样?

使用synchronize修饰的静态方法,那么同一时间只能有一个执行线程访问,但是其他线程可以访问这个对象的非静态方法。

synchronize修饰代码块

1、方法的其余部分保持在synchronize代码块之外,以获取更好的性能

2、synchronized修饰代码块的参数是当前对象,注意是对象,不是类

五、区别

1、java中每个对象都有同步锁,同步方法是指进入该方法时需要获取this对象的同步锁,而同步代码块则是可以指定需要获取哪个对象的同步锁

2、无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――同步方法很可能还会被其他线程的对象访问

六、测试同步方法

模拟场景:银行的账户,公司向账户转账,银行从账户扣除

package com.concurrent.threadSynchronize;

public class Account {

private double balance;

public double getBalance() {
return balance;
}

public void setBalance(double balance) {
this.balance = balance;
}

//向账户充值 amount
public synchronized void addAmount(double amount) {
double temp = balance;

try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}

temp += amount;
balance = temp;
}

//从账户取出amount
public synchronized void subtractAmount(double amount) {
double temp = balance;

try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
temp -= amount;
balance = temp;
}
}

package com.concurrent.threadSynchronize;

public class Bank implements Runnable{

private Account account;

public Bank(Account account) {
this.account = account;
}

//对账户进行扣除
@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.subtractAmount(1000);
}
}
}

package com.concurrent.threadSynchronize;

public class Company implements Runnable {

private Account account;

public Company(Account account) {
super();
this.account = account;
}

// 向账户充值
@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.addAmount(1000);
}
}
}

package com.concurrent.threadSynchronize;

public class Maintest {

public static void main(String[] args) {
Account account = new Account();
account.setBalance(1000);

Bank bank = new Bank(account);
Thread bankThread = new Thread(bank);

Company company = new Company(account);
Thread companyThread = new Thread(company);

System.out.println("Account initial : " + account.getBalance());

companyThread.start();
bankThread.start();

try {
companyThread.join();
bankThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Account Final : " + account.getBalance());
}
}




七、测试同步代码块

模拟场景:电影院售票,有两个播放室,多个售票处,一张电影票只能去特定的播放室使用

package com.concurrent.threadSynchronize;

/**
* 有两个播放室和两个售票处的电影院 一个售票处卖出的票只能在一个特定的播放室使用
*
* @author Nicholas
*
*/
public class Cinema {
private long vacanciesCinama1; //票量
private long vacanciesCinama2;

private final Object controlCineme1; //播放室
private final Object controlCineme2;

public Cinema() {
controlCineme1 = new Object();
controlCineme2 = new Object();
vacanciesCinama1 = 20;
vacanciesCinama2 = 20;
}

public boolean sellTickets1(int number) {
synchronized (controlCineme1) {
if (number < vacanciesCinama1) {
vacanciesCinama1 -= number;
return true;
} else {
return false;
}
}
}

public boolean sellTickets2(int number) {
synchronized (controlCineme2) {
if (number < vacanciesCinama2) {
vacanciesCinama2 -= number;
return true;
} else {
return false;
}
}
}

// 退票
public boolean returnTickets1(int number) {
synchronized (controlCineme1) {
vacanciesCinama1 += number;
return true;
}
}

// 退票
public boolean returnTickets2(int number) {
synchronized (controlCineme2) {
vacanciesCinama2 += number;
return true;
}
}

public long getVacanciesCinama1() {
return vacanciesCinama1;
}

public void setVacanciesCinama1(long vacanciesCinama1) {
this.vacanciesCinama1 = vacanciesCinama1;
}

// 返回当前剩余的票数

public long getVacanciesCinama2() {
return vacanciesCinama2;
}

public void setVacanciesCinama2(long vacanciesCinama2) {
this.vacanciesCinama2 = vacanciesCinama2;
}
}

package com.concurrent.threadSynchronize;

/**
* 售票处一
*
* @author Nicholas
*
*/
public class TicketsOffice1 implements Runnable {

private Cinema cinema;

public TicketsOffice1(Cinema cinema) {
this.cinema = cinema;
}

@Override
public void run() {
cinema.sellTickets1(2);// 卖出的票是在第一个电影播放室的
cinema.sellTickets1(3);
cinema.sellTickets2(2);// 卖出的票是在第二个播放室使用的

cinema.returnTickets1(1);
cinema.returnTickets2(1);

cinema.sellTickets1(2);
cinema.sellTickets1(3);

cinema.sellTickets2(2);
cinema.sellTickets2(3);
}
}

package com.concurrent.threadSynchronize;

/**
* 售票处一
*
* @author Nicholas
*
*/
public class TicketsOffice2 implements Runnable {

private Cinema cinema;

public TicketsOffice2(Cinema cinema) {
this.cinema = cinema;
}

@Override
public void run() {
cinema.sellTickets1(2);// 卖出的票是在第一个电影播放室的
cinema.sellTickets1(3);
cinema.sellTickets2(2);// 卖出的票是在第二个播放室使用的

cinema.returnTickets1(1);
cinema.returnTickets2(1);

cinema.sellTickets1(2);
cinema.sellTickets1(3);

cinema.sellTickets2(2);
cinema.sellTickets2(3);
}
}

package com.concurrent.threadSynchronize;

public class MianTest1 {

public static void main(String[] args) {
Cinema cinema = new Cinema();

TicketsOffice1 ticketsOffice1 = new TicketsOffice1(cinema);
Thread ticketsOffice1Thread = new Thread(ticketsOffice1);

TicketsOffice2 ticketsOffice2 = new TicketsOffice2(cinema);
Thread ticketsOffice2Thread = new Thread(ticketsOffice2);

ticketsOffice1Thread.start();
ticketsOffice2Thread.start();

try {
ticketsOffice1Thread.join();
ticketsOffice2Thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Room 1 Vacancies : "+cinema.getVacanciesCinama1());
System.out.println("Room 2 Vacancies : "+cinema.getVacanciesCinama2());
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: