同步块对象同步方法能更细粒度的锁定内容
同步锁:太大,容易造成效率低下,太小,锁不住
线程安全synchronized 尽可能锁定合理的范围(不是锁代码,而是锁数据)
双重检测
package com.wxh.syn;
//线程安全synchronized 尽可能锁定合理的范围(不是锁代码,而是锁数据)
public class Web12306 implements Runnable {
int numberKey = 10;
boolean flag = true;
public static void main(String[] args) {
Web12306 web = new Web12306();
new Thread(web,"马超").start();
new Thread(web,"关羽").start();
new Thread(web,"曹操").start();
}
public void run() {
test7();
}
//尽可能锁定合理范围,最合理的方法,双重检测
private void test7() {
while(flag) {
if(numberKey <= 0) { //判断还有没有票
flag = false;
return;
}
synchronized(this) { //因为对象为flag 和numberkey,锁住一个对象是不安全的,
if(numberKey <= 0) { //判断临界值,如当只有最后一张票时
flag = false;
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+numberKey--);
}
}
}
private void test5() {
while(flag) {
synchronized(this) { // a,b,c 三个线程,a拿到锁,进行判断,释放锁,B拿到锁,释放锁,a此时在sleep,B也进入sleep,
//但sleep结束,cpu调度可能先执行B,此时就会出现票数同时拿到
if(numberKey <= 0) {
flag = false;
return;
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+numberKey--);
}
}
private synchronized void test3() {
while(true) {
if(numberKey <= 0) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+numberKey--);
}
}
private void test2() {
while(flag) {
synchronized((Integer)numberKey) { //因为对象为flag 和numberkey,锁住一个对象是不安全的,
if(numberKey <= 0) {
flag = false;
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+numberKey--);
}
}
}
private void test() {
while(true) {
synchronized(this) { //线程安全,因为this对象包括了numberkey和flag
if(numberKey <= 0) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+numberKey--);
}
}
}
}
银行取钱,锁定银行账号:
package com.wxh.syn;
/**
* synchronized 锁执行完毕之后,才释放锁
* 因为银河存款100,可悲啊取走80后,剩余20不达到happy的他取钱90要求,return
* @author Administrator
* 代码块:更加精细控制
*/
public class UnsafeTest {
public static void main(String[] args) {
Account1 account = new Account1(170, "结婚礼金");
Drawing1 you = new Drawing1(account, 80, "可悲啊");
Drawing1 wif = new Drawing1(account, 90, "happy的他");
you.start();
wif.start();
}
}
//创建银行账户
class Account1{
int money;
String name;
public Account1(int money, String name) {
this.money = money;
this.name = name;
}
}
//模拟取款
class Drawing1 extends Thread{
Account1 account; //取钱的账户
int Outmoney; //取得钱数
int pagemoney; //取得总数
public Drawing1(Account1 account, int outmoney,String name) {
super(name);
this.account = account;
Outmoney = outmoney;
}
public void run() {
test();
}
//目标锁定不对,应该锁定对象(银行账号account)
private void test() {
if(account.money <= 0) { //提高性能的细节,因为每次线程进来都需要判断锁是否执行完之后再判断
return; //而这一步提前判断当银行余额为0时,不需要执行以下代码,大大提高了并发量。
}
synchronized(account) {
if(account.money -Outmoney <0) {
return;
}
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
account.money -= Outmoney; //账户余额
pagemoney = Outmoney;
System.out.println(this.getName()+"--->账户余额"+account.money);
System.out.println(this.getName()+"--->口袋金额"+pagemoney);
} //synchronized 锁执行完毕之后,才释放锁
}
}