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

一、临界区 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());
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值