一. 线程的创建
线程的创建方式有两种:
一种是继承Thread类,重写run()方法【这里的run()方法只是普通的方法】,在主方法中,创建该类的对象,调用对象的start()方法。
二种是实现Runnable接口,重写run()方法,在主方法中,以该实现类为参数,创建Thread线程,调用Thread的start()方法。
方式一:示例代码如下
1 public class Thread01 { 2 public static void main(String[] args) { 3 Cat cat = new Cat(); 4 System.out.println("main: "+Thread.currentThread().getName()); 5 cat.start(); 6 System.out.println("hello world"); 7 } 8 } 9 10 class Cat extends Thread{ 11 private int num = 0; 12 @Override 13 public void run() { 14 while(true){ 15 try { 16 sleep(1000); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 System.out.println("我的是小猫" + (++num)+"Thread: " + Thread.currentThread().getName()); 21 if(num >= 8){ 22 break; 23 } 24 } 25 } 26 }
方式二:示例代码如下
1 public class Thread03 { 2 public static void main(String[] args) { 3 Thread thread = new Thread(new Dog()); 4 thread.start(); 5 6 } 7 } 8 class Animal_ {} 9 class Dog extends Animal_ implements Runnable { 10 @Override 11 public void run() { 12 System.out.println("dog"); 13 } 14 }
方式二的另一种写法:【匿名内部类作为参数】
1 public class Thread03 { 2 public static void main(String[] args) { 3 4 // 使用匿名内部类,实现Runnable接口,重写run()方法,作为参数。 5 new Thread(new Runnable() { 6 @Override 7 public void run() { 8 System.out.println("main: " + Thread.currentThread().getName()); 9 } 10 }).start(); 14 } 15 } 16 class Animal_ {} 17 class Dog extends Animal_ implements Runnable { 18 @Override 19 public void run() { 20 System.out.println("dog"); 21 } 22 }
两种方式的区别,继承Thread类,只能是单一继承,接口可以实现多个,因此遇到已有继承父类的子类,则必须实现Runnable接口,来创建进程。
方式二的模拟代码如下【静态代理模式】:加深对方式二的理解
public class ProxyThreadTest { public static void main(String[] args) { Cat1 cat1 = new Cat1(); ProxyThread proxyThread = new ProxyThread(cat1);// 接口的多态 proxyThread.start(); } } class Animal{} // 单一继承,若想使用线程,实现Runnable接口. class Cat1 extends Animal implements Runnable { public Cat1() { } @Override public void run() { System.out.println("老虎嗷嗷叫"); } } class ProxyThread implements Runnable{ private Runnable target = null; @Override public void run() { if(target != null){ target.run(); // 动态绑定 } } public ProxyThread(Runnable target) { this.target = target; } public void start(){ start0(); } private void start0() { run(); } }
二. 线程的方法
start():开启线程
run():Runnable接口定义的方法,注意run()只是普通的方法,如果想让线程开始运作,应该是调用start()方法
yield():礼让【退让】,在cpu资源不足的情况下,让出自己的cpu和资源
join():插队,强制让调用该方法的线程执行
三. 守护线程
守护线程:主线程执行完毕,守护线程即使没有执行完成,也要结束
示例代码如下:
public class ThreadMethod01 { public static void main(String[] args) throws InterruptedException { MyDaemon myDaemon = new MyDaemon(); // 设置守护线程,必须在开启线程之前 myDaemon.setDaemon(true); myDaemon.start(); for(int i = 0;i < 10;i++){ System.out.println("宝强辛苦工作"); Thread.sleep(1000); } } } class MyDaemon extends Thread { @Override public void run() { for(;;){ try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(e.getMessage()); } System.out.println("马蓉宋喆聊天..."); } } }
四. 线程的生命周期
五. 互斥锁
我的理解互斥锁:对象锁和类锁
对象锁:用synchronized修饰普通方法【同步方法】或者在普通方法中修饰代码块【同步代码块】===>【锁在对象上】
类锁:用synchronized修饰静态方法【同步方法】或者在静态方法中修饰代码块【同步代码块】===>【锁在类上】
synchronized不能用来修饰变量。
六. 售票管理
三个窗口同时售票,票总数100张,打印出具体销售过程
1)实现Runnable接口实现
错误写法:
public class SellTicket { public static void main(String[] args) { Thread thread1 = new Thread(new SellTicketWin()); Thread thread2 = new Thread(new SellTicketWin()); Thread thread3 = new Thread(new SellTicketWin()); thread1.start(); thread2.start(); thread3.start(); } } class SellTicketWin extends Thread{ private int num = 100; private boolean loop = true; public void sell(){ if (num <= 0) { System.out.println(Thread.currentThread().getName() + "窗口,票卖完了"); loop = false; return; } try { Thread.sleep(50); } catch (InterruptedException e) { System.out.println(e.getMessage()); } System.out.println(Thread.currentThread().getName() + "窗口卖了一张票,剩余票数: " + (--num)); } @Override public void run() { while (loop) { sell(); } } }
此时是3个对象,分别对应一个线程,num不是唯一且共享的,不合题意。
正确写法:
SellTicketWin sellTicketWin = new SellTicketWin(); Thread thread1 = new Thread(sellTicketWin); Thread thread2 = new Thread(sellTicketWin); Thread thread3 = new Thread(sellTicketWin);
用唯一实现Runnable接口的类对象作为参数,保证num的唯一且共享。
如果不加锁,则运行结果如下:
Thread-0窗口卖了一张票,剩余票数: 99 Thread-1窗口卖了一张票,剩余票数: 97 Thread-2窗口卖了一张票,剩余票数: 98 Thread-2窗口卖了一张票,剩余票数: 96 Thread-0窗口卖了一张票,剩余票数: 95 Thread-1窗口卖了一张票,剩余票数: 94 Thread-2窗口卖了一张票,剩余票数: 93 Thread-0窗口卖了一张票,剩余票数: 91 Thread-1窗口卖了一张票,剩余票数: 92 Thread-0窗口卖了一张票,剩余票数: 90 Thread-1窗口卖了一张票,剩余票数: 89 Thread-2窗口卖了一张票,剩余票数: 88 Thread-0窗口卖了一张票,剩余票数: 87 Thread-1窗口卖了一张票,剩余票数: 86 Thread-2窗口卖了一张票,剩余票数: 85 Thread-0窗口卖了一张票,剩余票数: 84 Thread-1窗口卖了一张票,剩余票数: 83 Thread-2窗口卖了一张票,剩余票数: 82 Thread-0窗口卖了一张票,剩余票数: 80 Thread-1窗口卖了一张票,剩余票数: 81 Thread-2窗口卖了一张票,剩余票数: 79 Thread-0窗口卖了一张票,剩余票数: 77 Thread-1窗口卖了一张票,剩余票数: 78 Thread-2窗口卖了一张票,剩余票数: 76 Thread-0窗口卖了一张票,剩余票数: 75 Thread-1窗口卖了一张票,剩余票数: 75 Thread-2窗口卖了一张票,剩余票数: 74 Thread-1窗口卖了一张票,剩余票数: 73 Thread-0窗口卖了一张票,剩余票数: 72 Thread-2窗口卖了一张票,剩余票数: 71 Thread-0窗口卖了一张票,剩余票数: 70 Thread-1窗口卖了一张票,剩余票数: 69 Thread-2窗口卖了一张票,剩余票数: 68 Thread-1窗口卖了一张票,剩余票数: 67 Thread-0窗口卖了一张票,剩余票数: 67 Thread-2窗口卖了一张票,剩余票数: 66 Thread-0窗口卖了一张票,剩余票数: 65 Thread-1窗口卖了一张票,剩余票数: 65 Thread-2窗口卖了一张票,剩余票数: 64 Thread-1窗口卖了一张票,剩余票数: 63 Thread-0窗口卖了一张票,剩余票数: 63 Thread-2窗口卖了一张票,剩余票数: 62 Thread-1窗口卖了一张票,剩余票数: 61 Thread-0窗口卖了一张票,剩余票数: 61 Thread-2窗口卖了一张票,剩余票数: 60 Thread-0窗口卖了一张票,剩余票数: 59 Thread-1窗口卖了一张票,剩余票数: 58 Thread-2窗口卖了一张票,剩余票数: 57 Thread-0窗口卖了一张票,剩余票数: 55 Thread-1窗口卖了一张票,剩余票数: 56 Thread-2窗口卖了一张票,剩余票数: 54 Thread-0窗口卖了一张票,剩余票数: 53 Thread-1窗口卖了一张票,剩余票数: 52 Thread-2窗口卖了一张票,剩余票数: 51 Thread-0窗口卖了一张票,剩余票数: 50 Thread-1窗口卖了一张票,剩余票数: 50 Thread-2窗口卖了一张票,剩余票数: 49 Thread-1窗口卖了一张票,剩余票数: 48 Thread-0窗口卖了一张票,剩余票数: 48 Thread-2窗口卖了一张票,剩余票数: 47 Thread-0窗口卖了一张票,剩余票数: 46 Thread-1窗口卖了一张票,剩余票数: 46 Thread-2窗口卖了一张票,剩余票数: 45 Thread-0窗口卖了一张票,剩余票数: 43 Thread-1窗口卖了一张票,剩余票数: 44 Thread-2窗口卖了一张票,剩余票数: 42 Thread-0窗口卖了一张票,剩余票数: 40 Thread-1窗口卖了一张票,剩余票数: 41 Thread-2窗口卖了一张票,剩余票数: 39 Thread-1窗口卖了一张票,剩余票数: 38 Thread-0窗口卖了一张票,剩余票数: 38 Thread-2窗口卖了一张票,剩余票数: 37 Thread-0窗口卖了一张票,剩余票数: 36 Thread-1窗口卖了一张票,剩余票数: 35 Thread-2窗口卖了一张票,剩余票数: 34 Thread-1窗口卖了一张票,剩余票数: 33 Thread-0窗口卖了一张票,剩余票数: 33 Thread-2窗口卖了一张票,剩余票数: 32 Thread-0窗口卖了一张票,剩余票数: 31 Thread-1窗口卖了一张票,剩余票数: 31 Thread-2窗口卖了一张票,剩余票数: 30 Thread-1窗口卖了一张票,剩余票数: 29 Thread-0窗口卖了一张票,剩余票数: 29 Thread-2窗口卖了一张票,剩余票数: 28 Thread-1窗口卖了一张票,剩余票数: 27 Thread-0窗口卖了一张票,剩余票数: 27 Thread-2窗口卖了一张票,剩余票数: 26 Thread-0窗口卖了一张票,剩余票数: 24 Thread-1窗口卖了一张票,剩余票数: 25 Thread-2窗口卖了一张票,剩余票数: 23 Thread-1窗口卖了一张票,剩余票数: 22 Thread-0窗口卖了一张票,剩余票数: 21 Thread-2窗口卖了一张票,剩余票数: 20 Thread-1窗口卖了一张票,剩余票数: 19 Thread-0窗口卖了一张票,剩余票数: 18 Thread-2窗口卖了一张票,剩余票数: 17 Thread-0窗口卖了一张票,剩余票数: 16 Thread-1窗口卖了一张票,剩余票数: 15 Thread-2窗口卖了一张票,剩余票数: 14 Thread-1窗口卖了一张票,剩余票数: 13 Thread-0窗口卖了一张票,剩余票数: 13 Thread-2窗口卖了一张票,剩余票数: 12 Thread-0窗口卖了一张票,剩余票数: 11 Thread-1窗口卖了一张票,剩余票数: 10 Thread-2窗口卖了一张票,剩余票数: 9 Thread-1窗口卖了一张票,剩余票数: 8 Thread-0窗口卖了一张票,剩余票数: 7 Thread-2窗口卖了一张票,剩余票数: 6 Thread-1窗口卖了一张票,剩余票数: 5 Thread-0窗口卖了一张票,剩余票数: 4 Thread-2窗口卖了一张票,剩余票数: 3 Thread-1窗口卖了一张票,剩余票数: 2 Thread-0窗口卖了一张票,剩余票数: 1 Thread-2窗口卖了一张票,剩余票数: 0 Thread-2窗口,票卖完了 Thread-1窗口卖了一张票,剩余票数: -1 Thread-0窗口卖了一张票,剩余票数: -1
View Code
会有超票的风险,引入了锁,即synchronized关键字,如何使用呢?
注意,实现Runnable接口的实现类对象在main中只创建了一次,就当作创建3线程的参数,因此实现类对象是唯一的,由此想到对象锁
即 用synchronized修饰普通方法【同步方法】或者在普通方法中修饰代码块【同步代码块】===>【锁在对象上】
public class SellTicket { public static void main(String[] args) { SellTicketWin sellTicketWin = new SellTicketWin(); Thread thread1 = new Thread(sellTicketWin); Thread thread2 = new Thread(sellTicketWin); Thread thread3 = new Thread(sellTicketWin); thread1.start(); thread2.start(); thread3.start(); } } class SellTicketWin implements Runnable{ private int num = 100; private boolean loop = true; // 对象锁,上锁方式一: // 用synchronized修饰普通方法【同步方法】 // public synchronized void sell(){} public /*synchronized*/ void sell(){ // 对象锁,上锁方式二: // 在普通方法中,用synchronized修饰代码块【同步代码块】 // synchronized (this) {},()是对象名或者当前对象this. synchronized (/*this*/ (Integer)num) { if (num <= 0) { System.out.println(Thread.currentThread().getName() + "窗口,票卖完了"); loop = false; return; } try { Thread.sleep(50); } catch (InterruptedException e) { System.out.println(e.getMessage()); } System.out.println(Thread.currentThread().getName() + "窗口卖了一张票,剩余票数: " + (--num)); } } @Override public void run() { while (loop) { sell(); } } }
Thread-2窗口卖了一张票,剩余票数: 99 Thread-2窗口卖了一张票,剩余票数: 98 Thread-0窗口卖了一张票,剩余票数: 97 Thread-1窗口卖了一张票,剩余票数: 95 Thread-2窗口卖了一张票,剩余票数: 94 Thread-0窗口卖了一张票,剩余票数: 96 Thread-1窗口卖了一张票,剩余票数: 93 Thread-1窗口卖了一张票,剩余票数: 92 Thread-0窗口卖了一张票,剩余票数: 91 Thread-2窗口卖了一张票,剩余票数: 90 Thread-1窗口卖了一张票,剩余票数: 90 Thread-2窗口卖了一张票,剩余票数: 89 Thread-0窗口卖了一张票,剩余票数: 88 Thread-1窗口卖了一张票,剩余票数: 87 Thread-2窗口卖了一张票,剩余票数: 86 Thread-1窗口卖了一张票,剩余票数: 85 Thread-0窗口卖了一张票,剩余票数: 84 Thread-1窗口卖了一张票,剩余票数: 83 Thread-2窗口卖了一张票,剩余票数: 82 Thread-0窗口卖了一张票,剩余票数: 81 Thread-1窗口卖了一张票,剩余票数: 81 Thread-2窗口卖了一张票,剩余票数: 80 Thread-0窗口卖了一张票,剩余票数: 79 Thread-2窗口卖了一张票,剩余票数: 78 Thread-1窗口卖了一张票,剩余票数: 77 Thread-0窗口卖了一张票,剩余票数: 76 Thread-2窗口卖了一张票,剩余票数: 76 Thread-1窗口卖了一张票,剩余票数: 75 Thread-0窗口卖了一张票,剩余票数: 75 Thread-2窗口卖了一张票,剩余票数: 74 Thread-1窗口卖了一张票,剩余票数: 73 Thread-0窗口卖了一张票,剩余票数: 72 Thread-2窗口卖了一张票,剩余票数: 71 Thread-0窗口卖了一张票,剩余票数: 70 Thread-1窗口卖了一张票,剩余票数: 70 Thread-2窗口卖了一张票,剩余票数: 69 Thread-0窗口卖了一张票,剩余票数: 69 Thread-2窗口卖了一张票,剩余票数: 68 Thread-1窗口卖了一张票,剩余票数: 67 Thread-0窗口卖了一张票,剩余票数: 66 Thread-2窗口卖了一张票,剩余票数: 66 Thread-1窗口卖了一张票,剩余票数: 65 Thread-0窗口卖了一张票,剩余票数: 65 Thread-1窗口卖了一张票,剩余票数: 64 Thread-2窗口卖了一张票,剩余票数: 64 Thread-0窗口卖了一张票,剩余票数: 63 Thread-1窗口卖了一张票,剩余票数: 62 Thread-2窗口卖了一张票,剩余票数: 61 Thread-0窗口卖了一张票,剩余票数: 60 Thread-2窗口卖了一张票,剩余票数: 59 Thread-1窗口卖了一张票,剩余票数: 59 Thread-2窗口卖了一张票,剩余票数: 58 Thread-0窗口卖了一张票,剩余票数: 57 Thread-0窗口卖了一张票,剩余票数: 56 Thread-2窗口卖了一张票,剩余票数: 55 Thread-1窗口卖了一张票,剩余票数: 54 Thread-0窗口卖了一张票,剩余票数: 53 Thread-2窗口卖了一张票,剩余票数: 52 Thread-1窗口卖了一张票,剩余票数: 51 Thread-0窗口卖了一张票,剩余票数: 50 Thread-0窗口卖了一张票,剩余票数: 49 Thread-1窗口卖了一张票,剩余票数: 48 Thread-2窗口卖了一张票,剩余票数: 47 Thread-2窗口卖了一张票,剩余票数: 46 Thread-0窗口卖了一张票,剩余票数: 46 Thread-2窗口卖了一张票,剩余票数: 45 Thread-1窗口卖了一张票,剩余票数: 44 Thread-0窗口卖了一张票,剩余票数: 43 Thread-1窗口卖了一张票,剩余票数: 43 Thread-2窗口卖了一张票,剩余票数: 42 Thread-0窗口卖了一张票,剩余票数: 41 Thread-1窗口卖了一张票,剩余票数: 40 Thread-2窗口卖了一张票,剩余票数: 40 Thread-1窗口卖了一张票,剩余票数: 39 Thread-0窗口卖了一张票,剩余票数: 39 Thread-2窗口卖了一张票,剩余票数: 38 Thread-1窗口卖了一张票,剩余票数: 38 Thread-0窗口卖了一张票,剩余票数: 37 Thread-2窗口卖了一张票,剩余票数: 37 Thread-1窗口卖了一张票,剩余票数: 36 Thread-0窗口卖了一张票,剩余票数: 36 Thread-1窗口卖了一张票,剩余票数: 35 Thread-2窗口卖了一张票,剩余票数: 34 Thread-0窗口卖了一张票,剩余票数: 32 Thread-1窗口卖了一张票,剩余票数: 33 Thread-1窗口卖了一张票,剩余票数: 31 Thread-2窗口卖了一张票,剩余票数: 31 Thread-1窗口卖了一张票,剩余票数: 30 Thread-0窗口卖了一张票,剩余票数: 30 Thread-1窗口卖了一张票,剩余票数: 29 Thread-2窗口卖了一张票,剩余票数: 28 Thread-1窗口卖了一张票,剩余票数: 27 Thread-0窗口卖了一张票,剩余票数: 27 Thread-1窗口卖了一张票,剩余票数: 26 Thread-2窗口卖了一张票,剩余票数: 26 Thread-1窗口卖了一张票,剩余票数: 25 Thread-0窗口卖了一张票,剩余票数: 24 Thread-2窗口卖了一张票,剩余票数: 23 Thread-1窗口卖了一张票,剩余票数: 22 Thread-2窗口卖了一张票,剩余票数: 21 Thread-0窗口卖了一张票,剩余票数: 21 Thread-1窗口卖了一张票,剩余票数: 20 Thread-2窗口卖了一张票,剩余票数: 20 Thread-0窗口卖了一张票,剩余票数: 19 Thread-1窗口卖了一张票,剩余票数: 19 Thread-1窗口卖了一张票,剩余票数: 18 Thread-2窗口卖了一张票,剩余票数: 18 Thread-0窗口卖了一张票,剩余票数: 17 Thread-1窗口卖了一张票,剩余票数: 17 Thread-2窗口卖了一张票,剩余票数: 16 Thread-0窗口卖了一张票,剩余票数: 15 Thread-1窗口卖了一张票,剩余票数: 14 Thread-2窗口卖了一张票,剩余票数: 13 Thread-0窗口卖了一张票,剩余票数: 12 Thread-1窗口卖了一张票,剩余票数: 12 Thread-2窗口卖了一张票,剩余票数: 11 Thread-0窗口卖了一张票,剩余票数: 11 Thread-1窗口卖了一张票,剩余票数: 10 Thread-2窗口卖了一张票,剩余票数: 9 Thread-1窗口卖了一张票,剩余票数: 8 Thread-0窗口卖了一张票,剩余票数: 8 Thread-1窗口卖了一张票,剩余票数: 7 Thread-2窗口卖了一张票,剩余票数: 7 Thread-0窗口卖了一张票,剩余票数: 6 Thread-1窗口卖了一张票,剩余票数: 6 Thread-2窗口卖了一张票,剩余票数: 5 Thread-0窗口卖了一张票,剩余票数: 5 Thread-2窗口卖了一张票,剩余票数: 4 Thread-1窗口卖了一张票,剩余票数: 4 Thread-0窗口卖了一张票,剩余票数: 3 Thread-2窗口卖了一张票,剩余票数: 3 Thread-0窗口卖了一张票,剩余票数: 2 Thread-1窗口卖了一张票,剩余票数: 2 Thread-1窗口卖了一张票,剩余票数: 1 Thread-2窗口卖了一张票,剩余票数: 0 Thread-1窗口,票卖完了 Thread-2窗口,票卖完了 Thread-0窗口,票卖完了
View Code
可见运行结果完全正确。
2)继承Thread类实现
错误写法:
public class SellTicket { public static void main(String[] args) { SellTicketWin thread1 = new SellTicketWin(); SellTicketWin thread2 = new SellTicketWin(); SellTicketWin thread3 = new SellTicketWin(); thread1.start(); thread2.start(); thread3.start(); } } class SellTicketWin extends Thread{ private int num = 100; private boolean loop = true; public void sell(){ if (num <= 0) { System.out.println(Thread.currentThread().getName() + "窗口,票卖完了"); loop = false; return; } try { Thread.sleep(50); } catch (InterruptedException e) { System.out.println(e.getMessage()); } System.out.println(Thread.currentThread().getName() + "窗口卖了一张票,剩余票数: " + (--num)); } @Override public void run() { while (loop) { sell(); } } }
此时,是3个对象,3个num成员,这里的num并不是唯一且共享的,不合题意。
正确写法:
private static int num = 100; private static boolean loop = true;
使用static关键字,使得num变成静态变量,随着类的加载而加载,唯一且共享。
如果不加锁,运行结果如下:
Thread-1窗口卖了一张票,剩余票数: 99 Thread-0窗口卖了一张票,剩余票数: 97 Thread-2窗口卖了一张票,剩余票数: 98 Thread-2窗口卖了一张票,剩余票数: 96 Thread-0窗口卖了一张票,剩余票数: 95 Thread-1窗口卖了一张票,剩余票数: 94 Thread-2窗口卖了一张票,剩余票数: 93 Thread-1窗口卖了一张票,剩余票数: 92 Thread-0窗口卖了一张票,剩余票数: 91 Thread-1窗口卖了一张票,剩余票数: 89 Thread-2窗口卖了一张票,剩余票数: 90 Thread-0窗口卖了一张票,剩余票数: 88 Thread-0窗口卖了一张票,剩余票数: 87 Thread-1窗口卖了一张票,剩余票数: 86 Thread-2窗口卖了一张票,剩余票数: 85 Thread-2窗口卖了一张票,剩余票数: 84 Thread-1窗口卖了一张票,剩余票数: 83 Thread-0窗口卖了一张票,剩余票数: 82 Thread-2窗口卖了一张票,剩余票数: 81 Thread-0窗口卖了一张票,剩余票数: 80 Thread-1窗口卖了一张票,剩余票数: 79 Thread-2窗口卖了一张票,剩余票数: 78 Thread-1窗口卖了一张票,剩余票数: 77 Thread-0窗口卖了一张票,剩余票数: 76 Thread-1窗口卖了一张票,剩余票数: 75 Thread-0窗口卖了一张票,剩余票数: 74 Thread-2窗口卖了一张票,剩余票数: 73 Thread-2窗口卖了一张票,剩余票数: 72 Thread-1窗口卖了一张票,剩余票数: 72 Thread-0窗口卖了一张票,剩余票数: 71 Thread-2窗口卖了一张票,剩余票数: 70 Thread-1窗口卖了一张票,剩余票数: 68 Thread-0窗口卖了一张票,剩余票数: 69 Thread-0窗口卖了一张票,剩余票数: 67 Thread-1窗口卖了一张票,剩余票数: 66 Thread-2窗口卖了一张票,剩余票数: 65 Thread-1窗口卖了一张票,剩余票数: 64 Thread-0窗口卖了一张票,剩余票数: 63 Thread-2窗口卖了一张票,剩余票数: 62 Thread-1窗口卖了一张票,剩余票数: 61 Thread-0窗口卖了一张票,剩余票数: 61 Thread-2窗口卖了一张票,剩余票数: 60 Thread-1窗口卖了一张票,剩余票数: 59 Thread-0窗口卖了一张票,剩余票数: 58 Thread-2窗口卖了一张票,剩余票数: 57 Thread-0窗口卖了一张票,剩余票数: 56 Thread-1窗口卖了一张票,剩余票数: 56 Thread-2窗口卖了一张票,剩余票数: 55 Thread-1窗口卖了一张票,剩余票数: 53 Thread-0窗口卖了一张票,剩余票数: 54 Thread-2窗口卖了一张票,剩余票数: 52 Thread-1窗口卖了一张票,剩余票数: 51 Thread-0窗口卖了一张票,剩余票数: 51 Thread-2窗口卖了一张票,剩余票数: 50 Thread-0窗口卖了一张票,剩余票数: 48 Thread-1窗口卖了一张票,剩余票数: 49 Thread-2窗口卖了一张票,剩余票数: 47 Thread-1窗口卖了一张票,剩余票数: 46 Thread-0窗口卖了一张票,剩余票数: 45 Thread-2窗口卖了一张票,剩余票数: 44 Thread-0窗口卖了一张票,剩余票数: 43 Thread-1窗口卖了一张票,剩余票数: 42 Thread-2窗口卖了一张票,剩余票数: 41 Thread-1窗口卖了一张票,剩余票数: 39 Thread-0窗口卖了一张票,剩余票数: 40 Thread-2窗口卖了一张票,剩余票数: 38 Thread-1窗口卖了一张票,剩余票数: 37 Thread-0窗口卖了一张票,剩余票数: 36 Thread-2窗口卖了一张票,剩余票数: 35 Thread-0窗口卖了一张票,剩余票数: 34 Thread-1窗口卖了一张票,剩余票数: 33 Thread-2窗口卖了一张票,剩余票数: 32 Thread-0窗口卖了一张票,剩余票数: 31 Thread-1窗口卖了一张票,剩余票数: 30 Thread-2窗口卖了一张票,剩余票数: 29 Thread-0窗口卖了一张票,剩余票数: 28 Thread-1窗口卖了一张票,剩余票数: 28 Thread-2窗口卖了一张票,剩余票数: 27 Thread-1窗口卖了一张票,剩余票数: 26 Thread-0窗口卖了一张票,剩余票数: 25 Thread-2窗口卖了一张票,剩余票数: 24 Thread-0窗口卖了一张票,剩余票数: 23 Thread-1窗口卖了一张票,剩余票数: 23 Thread-2窗口卖了一张票,剩余票数: 22 Thread-1窗口卖了一张票,剩余票数: 21 Thread-0窗口卖了一张票,剩余票数: 20 Thread-2窗口卖了一张票,剩余票数: 19 Thread-0窗口卖了一张票,剩余票数: 18 Thread-1窗口卖了一张票,剩余票数: 17 Thread-2窗口卖了一张票,剩余票数: 16 Thread-1窗口卖了一张票,剩余票数: 15 Thread-0窗口卖了一张票,剩余票数: 14 Thread-2窗口卖了一张票,剩余票数: 13 Thread-0窗口卖了一张票,剩余票数: 12 Thread-1窗口卖了一张票,剩余票数: 11 Thread-2窗口卖了一张票,剩余票数: 10 Thread-0窗口卖了一张票,剩余票数: 9 Thread-1窗口卖了一张票,剩余票数: 8 Thread-2窗口卖了一张票,剩余票数: 7 Thread-1窗口卖了一张票,剩余票数: 6 Thread-0窗口卖了一张票,剩余票数: 6 Thread-2窗口卖了一张票,剩余票数: 5 Thread-1窗口卖了一张票,剩余票数: 3 Thread-0窗口卖了一张票,剩余票数: 4 Thread-2窗口卖了一张票,剩余票数: 2 Thread-0窗口卖了一张票,剩余票数: 1 Thread-0窗口,票卖完了 Thread-1窗口卖了一张票,剩余票数: 0 Thread-2窗口卖了一张票,剩余票数: -1 Process finished with exit code 0
View Code
会有超票现象,此时num是静态变量,由此想到加类锁
即用synchronized修饰静态方法【同步方法】或者在静态方法中修饰代码块【同步代码块】===>【锁在类上】
public class SellTicket { public static void main(String[] args) { SellTicketWin thread1 = new SellTicketWin(); SellTicketWin thread2 = new SellTicketWin(); SellTicketWin thread3 = new SellTicketWin(); thread1.start(); thread2.start(); thread3.start(); } } class SellTicketWin extends Thread{ private static int num = 100; private static boolean loop = true; // 类锁方式一:将sell改为静态方法,并且用synchronized修饰【同步方法】 // public static synchronized void sell(){} public static /*synchronized*/ void sell(){ // 类锁方式二:在静态方法中,用synchronized修饰代码块【同步代码块】 // synchronized (SellTicketWin.class) {},()是类名.class synchronized (SellTicketWin.class) { if (num <= 0) { System.out.println(Thread.currentThread().getName() + "窗口,票卖完了"); loop = false; return; } try { Thread.sleep(50); } catch (InterruptedException e) { System.out.println(e.getMessage()); } System.out.println(Thread.currentThread().getName() + "窗口卖了一张票,剩余票数: " + (--num)); } } @Override public void run() { while (loop) { sell(); } } }
Thread-2窗口卖了一张票,剩余票数: 99 Thread-2窗口卖了一张票,剩余票数: 98 Thread-2窗口卖了一张票,剩余票数: 97 Thread-2窗口卖了一张票,剩余票数: 96 Thread-2窗口卖了一张票,剩余票数: 95 Thread-2窗口卖了一张票,剩余票数: 94 Thread-2窗口卖了一张票,剩余票数: 93 Thread-2窗口卖了一张票,剩余票数: 92 Thread-2窗口卖了一张票,剩余票数: 91 Thread-1窗口卖了一张票,剩余票数: 90 Thread-0窗口卖了一张票,剩余票数: 89 Thread-1窗口卖了一张票,剩余票数: 88 Thread-1窗口卖了一张票,剩余票数: 87 Thread-1窗口卖了一张票,剩余票数: 86 Thread-2窗口卖了一张票,剩余票数: 85 Thread-2窗口卖了一张票,剩余票数: 84 Thread-2窗口卖了一张票,剩余票数: 83 Thread-1窗口卖了一张票,剩余票数: 82 Thread-1窗口卖了一张票,剩余票数: 81 Thread-0窗口卖了一张票,剩余票数: 80 Thread-0窗口卖了一张票,剩余票数: 79 Thread-0窗口卖了一张票,剩余票数: 78 Thread-0窗口卖了一张票,剩余票数: 77 Thread-1窗口卖了一张票,剩余票数: 76 Thread-2窗口卖了一张票,剩余票数: 75 Thread-2窗口卖了一张票,剩余票数: 74 Thread-2窗口卖了一张票,剩余票数: 73 Thread-2窗口卖了一张票,剩余票数: 72 Thread-2窗口卖了一张票,剩余票数: 71 Thread-2窗口卖了一张票,剩余票数: 70 Thread-1窗口卖了一张票,剩余票数: 69 Thread-1窗口卖了一张票,剩余票数: 68 Thread-1窗口卖了一张票,剩余票数: 67 Thread-0窗口卖了一张票,剩余票数: 66 Thread-0窗口卖了一张票,剩余票数: 65 Thread-1窗口卖了一张票,剩余票数: 64 Thread-2窗口卖了一张票,剩余票数: 63 Thread-2窗口卖了一张票,剩余票数: 62 Thread-2窗口卖了一张票,剩余票数: 61 Thread-1窗口卖了一张票,剩余票数: 60 Thread-1窗口卖了一张票,剩余票数: 59 Thread-1窗口卖了一张票,剩余票数: 58 Thread-1窗口卖了一张票,剩余票数: 57 Thread-1窗口卖了一张票,剩余票数: 56 Thread-1窗口卖了一张票,剩余票数: 55 Thread-0窗口卖了一张票,剩余票数: 54 Thread-1窗口卖了一张票,剩余票数: 53 Thread-2窗口卖了一张票,剩余票数: 52 Thread-2窗口卖了一张票,剩余票数: 51 Thread-2窗口卖了一张票,剩余票数: 50 Thread-2窗口卖了一张票,剩余票数: 49 Thread-2窗口卖了一张票,剩余票数: 48 Thread-2窗口卖了一张票,剩余票数: 47 Thread-2窗口卖了一张票,剩余票数: 46 Thread-2窗口卖了一张票,剩余票数: 45 Thread-1窗口卖了一张票,剩余票数: 44 Thread-1窗口卖了一张票,剩余票数: 43 Thread-0窗口卖了一张票,剩余票数: 42 Thread-1窗口卖了一张票,剩余票数: 41 Thread-2窗口卖了一张票,剩余票数: 40 Thread-2窗口卖了一张票,剩余票数: 39 Thread-2窗口卖了一张票,剩余票数: 38 Thread-2窗口卖了一张票,剩余票数: 37 Thread-2窗口卖了一张票,剩余票数: 36 Thread-2窗口卖了一张票,剩余票数: 35 Thread-2窗口卖了一张票,剩余票数: 34 Thread-2窗口卖了一张票,剩余票数: 33 Thread-1窗口卖了一张票,剩余票数: 32 Thread-0窗口卖了一张票,剩余票数: 31 Thread-1窗口卖了一张票,剩余票数: 30 Thread-1窗口卖了一张票,剩余票数: 29 Thread-2窗口卖了一张票,剩余票数: 28 Thread-2窗口卖了一张票,剩余票数: 27 Thread-1窗口卖了一张票,剩余票数: 26 Thread-1窗口卖了一张票,剩余票数: 25 Thread-0窗口卖了一张票,剩余票数: 24 Thread-1窗口卖了一张票,剩余票数: 23 Thread-2窗口卖了一张票,剩余票数: 22 Thread-1窗口卖了一张票,剩余票数: 21 Thread-1窗口卖了一张票,剩余票数: 20 Thread-0窗口卖了一张票,剩余票数: 19 Thread-1窗口卖了一张票,剩余票数: 18 Thread-1窗口卖了一张票,剩余票数: 17 Thread-1窗口卖了一张票,剩余票数: 16 Thread-1窗口卖了一张票,剩余票数: 15 Thread-1窗口卖了一张票,剩余票数: 14 Thread-2窗口卖了一张票,剩余票数: 13 Thread-2窗口卖了一张票,剩余票数: 12 Thread-2窗口卖了一张票,剩余票数: 11 Thread-2窗口卖了一张票,剩余票数: 10 Thread-2窗口卖了一张票,剩余票数: 9 Thread-1窗口卖了一张票,剩余票数: 8 Thread-0窗口卖了一张票,剩余票数: 7 Thread-0窗口卖了一张票,剩余票数: 6 Thread-1窗口卖了一张票,剩余票数: 5 Thread-2窗口卖了一张票,剩余票数: 4 Thread-2窗口卖了一张票,剩余票数: 3 Thread-1窗口卖了一张票,剩余票数: 2 Thread-0窗口卖了一张票,剩余票数: 1 Thread-1窗口卖了一张票,剩余票数: 0 Thread-1窗口,票卖完了 Thread-2窗口,票卖完了 Thread-0窗口,票卖完了
View Code
可见运行结果完全正确。
转自:https://www.cnblogs.com/zwgitOne123/p/17027304.html