package com.ldp.demo.Thread; public class Ticket_Synchronized { public static void main(String[] args) { Ticket_tation ticket = new Ticket_tation(); new Thread(ticket, "a") { }.start(); new Thread(ticket, "b") { }.start(); new Thread(ticket, "c") { }.start(); new Thread(ticket, "d") { }.start(); } } class Ticket_tation implements Runnable { private int ticketNum = 10; @Override public void run() { while (ticketNum > 0) { //while和synchronized 的位置不能互换, synchronized (this) { //要不然票会一直是同一个窗口出票 //synchronized 在这里锁的是对象 if (ticketNum==0){ System.out.println( Thread.currentThread().getName()+"出票失败,"+"票已售完!" ); return; } try { Thread.sleep(50);//睡眠50毫秒,要不然执行太快,会是同一个窗口出票 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println((ticketNum--) + "号票已售出!" + Thread.currentThread().getName()); } } } }
结果
10号票已售出!a
9号票已售出!d
8号票已售出!d
7号票已售出!c
6号票已售出!b
5号票已售出!b
4号票已售出!c
3号票已售出!c
2号票已售出!c
1号票已售出!d
a出票失败,票已售完!
c出票失败,票已售完!
b出票失败,票已售完!
这种方式效率太低,因为synchronized(this)锁住的是对象,代码块里所有的内容都被阻塞了,耗费时间,可以改为锁具体操作,即锁扣除票数方法substract_ticket();
package com.ldp.demo.Thread; public class Ticket_Synchronized { public static void main(String[] args) { Ticket_tation ticket = new Ticket_tation(); new Thread(ticket, "a") { }.start(); new Thread(ticket, "b") { }.start(); new Thread(ticket, "c") { }.start(); new Thread(ticket, "d") { }.start(); } } class Ticket_tation implements Runnable { private int ticketNum = 3; public synchronized Result substract_ticket() { if (ticketNum == 0) { return new Result(false, ticketNum); } return new Result(true, ticketNum--); } @Override public void run() { while (ticketNum > 0) { if (ticketNum == 0) { System.out.println(Thread.currentThread().getName() + "出票失败," + "票已售完!"); return; } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Result result = substract_ticket(); if (!result.isFlag()) { System.out.println(Thread.currentThread().getName() + "出票失败," + "票已售完!"); return; } System.out.println(result.getCount() + "号票已售出!" + Thread.currentThread().getName()); } } } class Result { boolean flag; int count; public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public Result() { } public Result(boolean flag, int count) { this.flag = flag; this.count = count; } }
3号票已售出!a
2号票已售出!d
b出票失败,票已售完!
1号票已售出!c
a出票失败,票已售完!
synchronized锁的是非静态方法也叫对象锁。
多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。(java对象的内存地址是否相同)
synchronized修饰静态的方法也叫类锁
1,要满足方法同步(或者代码块同步)就必须保证多线程访问的是同一个对象(在java内存中的地址是否相同)。
2,类锁和对象锁同时存在时,多线程访问时不会阻塞,因为他们不是一个锁。
假如有两个火车站,每个火车站有两个窗口售票,那就不能锁对象了,要锁具体操作的方法了。
package com.ldp.demo.Thread; import org.apache.commons.lang3.time.StopWatch; /** * 多个火车站多个窗口售票 */ public class ThreadTicket { private static final int NUM = 7; public static int getNum() { return NUM; } public static void main(String[] args) { Ticket.getTicket().setTicketNum(NUM); TicketStation station1 = new TicketStation("南火车站"); TicketStation station2 = new TicketStation("西火车站"); new Thread(station1, "西窗口一").start(); new Thread(station2, "南窗口二").start(); new Thread(station2, "西窗口一").start(); new Thread(station1, "南窗口二").start(); } } class Ticket { private static final Ticket ticket = new Ticket(); public Ticket() { } public static Ticket getTicket() { return ticket; } private int TicketNum; public int getTicketNum() { return TicketNum; } public void setTicketNum(int ticketNum) { this.TicketNum = ticketNum; } public synchronized Result substratTicket() { Result result = new Result(); if (TicketNum == 0) { result.setFlag(false); result.setCount(TicketNum); } else { result.setFlag(true); result.setCount(TicketNum); --TicketNum; } return result; } } class TicketStation implements Runnable { private String name; public String getName() { return name; } public TicketStation() { } public TicketStation(String name) { this.name = name; } @Override public void run() { while (Ticket.getTicket().getTicketNum() > 0) { if (Ticket.getTicket().getTicketNum() == 0) { break; } try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } Result result = Ticket.getTicket().substratTicket(); if (result.isFlag()) { Out.getInstance().write(System.currentTimeMillis(), this, Thread.currentThread().getName(), result.getCount()); } else { System.out.println(System.currentTimeMillis() + this.name + Thread.currentThread().getName() + "出票失败"); } } } } class Result { boolean flag; int count; public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public Result() { } public Result(boolean flag, int count) { this.flag = flag; this.count = count; } }
package com.ldp.demo.Thread; class Out{ private final static Out out=new Out(); private Out(){} public static Out getInstance(){ return out; } static void write(long time,TicketStation station,String adress,int count){ System.out.println(time+ station.getName()+"在"+adress+"卖出了第"+(ThreadTicket.getNum()-count+1)+"票"); } }