方法一:同步代码块
Accoun
package com.bjsxt.synch1;/*** 银行账户类*/
public class Account {private int balance = 600;//余额/*** 取款* @param money*/public void withDraw(int money){this.balance = this.balance -money;}/*** 查看余额* @return*/public int getBalance(){return balance;}
}
取款线程
package com.bjsxt.synch1;/*** 取款的线程** 线程同步方式1:同步代码块** 总结1:认识同步监视器(锁子)* synchronized(同步监视器){ }* 1)必须是引用数据类型,不能是基本数据类型* 2)在同步代码块中可以改变同步监视器对象的值,不能改变其引用* 3)尽量不要String和包装类Integer做同步监视器.如果使用了,只要保证代码块中不对其进行任何操作也没有关系* 4)一般使用共享资源做同步监视器即可* 5)也可以创建一个专门的同步监视器,没有任何业务含义* 6)建议使用final修饰同步监视器** 总结2:同步代码块的执行过程* 1)第一个线程来到同步代码块,发现同步监视器open状态,需要close,然后执行其中的代码* 2)第一个线程执行过程中,发生了线程切换(阻塞 就绪),第一个线程失去了cpu,但是没有开锁open* 3)第二个线程获取了cpu,来到了同步代码块,发现同步监视器close状态,无法执行其中的代码,第二个线程也进入阻塞状态* 4)第一个线程再次获取CPU,接着执行后续的代码;同步代码块执行完毕,释放锁open* 5)第二个线程也再次获取cpu,来到了同步代码块,发现同步监视器open状态,重复第一个线程的处理过程(加锁)* 强调:同步代码块中能发生线程切换吗?能!!! 但是后续的被执行的线程也无法执行同步代码块(锁仍旧close)* 总结3:线程同步 优点和缺点* 优点:安全* 缺点:效率低下 可能出现死锁* * 总结4:其他* 1)多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块,其他线程无法访问其中的任何一个代码块* 2)多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块, 但是没有锁住使用其他同步监视器的代码块,其他线程有机会访问其他同步监视器的代码块*/
public class AccountRunnable implements Runnable{private final Account account = new Account();final Object obj = new Object();//byte [] buf = new byte[1];//final String str = "bjsxt";//final Integer in = 1234;//int n = 5;/*** 线程体:取款的步骤*/@Overridepublic void run() {//此处省略200句synchronized (account){if(account.getBalance()>=400){//余额足够 临界代码try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//就取款account.withDraw(400);System.out.println(Thread.currentThread().getName()+"取款成功,当前余额:"+account.getBalance());}else{//余额不足//给出提示System.out.println(Thread.currentThread().getName()+"取款失败,余额不足,当前余额:"+account.getBalance());}}//此处省略100句}public void method1(){synchronized (account){}}public void method2(){synchronized (obj){}}public void method3(){synchronized (obj){}}
}
main
package com.bjsxt.synch1;public class TestAccount {public static void main(String[] args) {//创建两个线程,模拟两个用户Runnable runnable = new AccountRunnable();Thread thread1 = new Thread(runnable,"张三");Thread thread2 = new Thread(runnable,"张三妻子");//启动两个线程,模拟两个用户取款thread1.start();thread2.start();}
}
方法二:同步方法
银行账户类
package com.bjsxt.synch2;/*** 银行账户类*/
public class Account {private int balance = 600;//余额/*** 取款* @param money*/public void withDraw(int money){this.balance = this.balance -money;}/*** 查看余额* @return*/public int getBalance(){return balance;}
}
取款的线程
package com.bjsxt.synch2;/*** 取款的线程*方式2:同步方法** 1.不要给run()加锁* 2. 非静态同步方法的锁:this* 静态同步方法的锁:类名.class* 3.同步方法和同步代码块哪种效率高* 同步代码块效率高**/
public class AccountRunnable implements Runnable{private Account account = new Account();/*** 线程体:取款的步骤*/@Overridepublic void run() {//此处省略200句//取款withDraw();//此处省略100句}public synchronized void withDraw(){ //非静态同步方法的锁是thisif(account.getBalance()>=400){ //余额足够 临界代码try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//就取款account.withDraw(400);System.out.println(Thread.currentThread().getName()+"取款成功,当前余额:"+account.getBalance());}else{//余额不足//给出提示System.out.println(Thread.currentThread().getName()+"取款失败,余额不足,当前余额:"+account.getBalance());}}public synchronized void method1(){ //this}public synchronized void method2(){ //this// Vector v;}public synchronized static void method3(){ //静态的同步方法的锁是类名.class 类对象 AccountRunnable.class//Class clazz = AccountRunnable.class;}public synchronized static void method4(){}
}
main
package com.bjsxt.synch2;public class TestAccount {public static void main(String[] args) {//创建两个线程,模拟两个用户Runnable runnable = new AccountRunnable();Thread thread1 = new Thread(runnable,"张三");Thread thread2 = new Thread(runnable,"张三妻子");//启动两个线程,模拟两个用户取款thread1.start();thread2.start();}
}
方法三:锁
银行账户类
package com.bjsxt.synch3;/*** 银行账户类*/
public class Account {private int balance = 600;//余额/*** 取款* @param money*/public void withDraw(int money){this.balance = this.balance -money;}/*** 查看余额* @return*/public int getBalance(){return balance;}
}
取款的线程
package com.bjsxt.synch3;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 取款的线程*/
public class AccountRunnable implements Runnable{private Account account = new Account();//购买一把锁private Lock lock = new ReentrantLock();//Re-entrant-Lock //entrance 可重入锁/*** 线程体:取款的步骤*/@Overridepublic void run() {//此处省略200句//上锁lock.lock();try{if(account.getBalance()>=400){//余额足够 临界代码try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//就取款account.withDraw(400);System.out.println(Thread.currentThread().getName()+"取款成功,当前余额:"+account.getBalance());}else{//余额不足//给出提示System.out.println(Thread.currentThread().getName()+"取款失败,余额不足,当前余额:"+account.getBalance());}method1();}finally{//解锁lock.unlock();}//此处省略100句}public void method1(){lock.lock();try{method2();}finally{lock.unlock();}}public void method2(){lock.lock();try{}finally{lock.unlock();}}
}
main
package com.bjsxt.synch3;public class TestAccount {public static void main(String[] args) {//创建两个线程,模拟两个用户Runnable runnable = new AccountRunnable();Thread thread1 = new Thread(runnable,"张三");Thread thread2 = new Thread(runnable,"张三妻子");//启动两个线程,模拟两个用户取款thread1.start();thread2.start();}
}