应用场景:多用户对同一银行账户进行取款
取款线程类,每个用户对应一个线程对象
多个用户共享同一个银行账户,使用Runnable解决
对于具体的实现过程中出现冲突问题时,是由于当一个账户判断银行账户中的数目大于给定值可以取款时,这时将cpu释放出去,去执行另一个线程,另一个线程执行完后,回到该线程继续执行时,实际账户中的数目已经不够但是因为之前已经判断,所以还会接着执行下去,这时就会出错。为了解决这个问题
同步代码块synchronized(同步监视器){ * 必须是引用数据类型,不能是基本数据类型 * 在同步代码块中可以改变同步监视对象的值,但是不能改变其引用 * //account=new account * 建议使用final来修饰同步监视器 * 尽量不要使用String和包装类来做同步监视器 * 可以创建一个专门的同步监视器没有任何含义 * 共享资源用来做锁
将一定不能分开的放在synchronized(){}里面
synchronized (account){}
第一个线程来到同步代码块,发现同步监视器是open状态,关闭,然后执行其中的代码
第一个线程执行过程中,发生了线程切换(阻塞 就绪),第一个线程失去cpu,但是没有开锁
第二个线程获取cpu,来到同步代码块,发现同步监视器是close状态,无法执行其中的代码,第二个线程也进入阻塞状态
第一个线程再次获取cpu,来到同步代码块,继续执行后续代码,同步代码执行完毕,释放锁open
第二线程发现同步监视器是open状态,拿到锁并将锁变为close状态,有阻塞态进入就绪态,在进入运行态
优点:安全
缺点:效率低 可能出现死锁
同步方法定义的方法上面加synchronized()
public void run() { //取款 withdraw(); } public synchronized void withdraw() { //同步方法的锁 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()); } } public synchronized static void method1() { //静态的同步方法的锁是类名.class 类对象AccountRunnable Class clazz=AccountRunnable.class; } public synchronized static void method2() { }
注意:
*非静态同步方法的锁:this
* 静态同步方法的锁:类名.class
*3.同步方法和同步代码块谁的效率高 : 同步代码块效率高
Lock锁注意:如果同步代码有异常,要将unlock()写入finally语句块
Reentrantlock 可重入锁 会做一个计数
首先需要创建锁
private Lock lock = new ReentrantLock(); 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()); } } finally { //解锁 lock.unlock(); }线程同步练习:4个窗口卖100张票
使用同步代码块,不能够将while都放在同步代码块中,这样会使得一个线程全部执行完
锁的只能是执行一次
package synch4; public class TicketRunnalble1 implements Runnable{ private int ticketnum = 100; @Override public void run() { while (true) { synchronized (this) { if (ticketnum <= 0) { break; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出了第" + (100 - ticketnum+1) + "张票"); ticketnum--; } } } public static void main(String[] args) { Runnable runnable = new TicketRunnalble1(); //创建4个线程模拟4个窗口 Thread thread1 = new Thread(runnable); Thread thread2= new Thread(runnable); Thread thread3 = new Thread(runnable); Thread thread4 = new Thread(runnable); thread1.setName("thread1"); thread2.setName("thread2"); thread3.setName("thread3"); thread4.setName("thread4"); //窗口开始买票(启动线程) thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }同步方法
public class TicketRunnalble2 implements Runnable{ private int ticketnum = 100; @Override public void run() { while (ticketnum>0) { sellOne(); } } public synchronized void sellOne() { if (ticketnum <= 0) { return; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出了第" + (100 - ticketnum+1) + "张票"); ticketnum--; }lock锁
private int ticketnum = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { //上锁 lock.lock(); try{ if (ticketnum <= 0) { break; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出了第" + (100 - ticketnum + 1) + "张票"); ticketnum--; }finally { lock.unlock(); } } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)