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;
/**
* 有两个播放室和两个售票处的电影院 一个售票处卖出的票只能在一个特定的播放室使用
*
* @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;
}
}
临界区是一个用以访问共享资源的代码块,这个代码块在同一时间内只允许一个线程执行
二、同步
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()); } }
相关文章推荐
- 解决java压缩图片透明背景变黑色的问题
- 解决java压缩图片透明背景变黑色的问题
- java对象的强引用,软引用,弱引用和虚引用
- eclipse常用插件
- 黑马程序元----集合框架
- java 框架基础知识(3)----PropertyEditor-->Spring IoC
- 初学Java之基本类型
- spring实战二之Bean的自动装配(非注解方式)
- 初学Java之基本类型
- 初学Java之AAWT组件库2
- 初学Java之AAWT组件库
- java 自定义异常
- 杭电ACM2025java做法
- 初学Java之LayoutManager
- 初学Java之Button
- Java中Runnable和Thread的区别的疑问
- java成员内部类、局部内部类、静态内部类和匿名内部类
- struts2中struts.xml中的action标签的method属性配置为"{1}"的时候是什么意味
- java内部类的作用
- 第2章 Java程序设计环境