最新要闻
- 水里也能开!仰望U8核心系统支持IP68防水:可浮水行驶
- 百万级纯电性能超跑!比亚迪仰望U9来了:零百加速2秒级、电动蝴蝶门
- 对标比亚迪仰望U8 东风猛士M-Terrain官图发布:超级硬汉
- 时隔18年再出续篇!经典老片《神话》续集定名《传说》
- 144MB缓存性能无解!Zen4架构AMD锐龙9 7950X3D比酷睿i9-13900K快了52%
- 荣耀Magic 5系列镜头模组曝光:经典圆形设计、配100X长焦
- 每日观点:地表最快!realme宣布首发量产240W满级秒充:充满不到10分钟
- 李国庆称腾讯京东有大公司病 当当就是失败的案例
- 98年哥哥返乡给15个弟妹买一车礼物:塞满整个后备箱
- 荣耀MagicOS获新浪2022科技风云榜年度智能操作系统奖
- 锐龙9 6900HX加持!魔方M600迷你主机图赏
- 【世界报资讯】便宜还好用:绿联iPhone全系钢化膜冲量3.6元/张
- 世界速看:折叠屏我只认OPPO Find N2:安卓阵营独一无二
- 环球聚焦:宝马展示i Vision Dee概念汽车:可变换车身颜色 有科幻味了
- 全球视点!员工:不怕大家拿任何手机跟一加11比精致度和质感
- 天天快资讯丨天府可乐因破产传闻销量暴增 民族品牌不会轻易垮:请理性消费
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
java中的多线程
一. 线程的创建
线程的创建方式有两种:
一种是继承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 @Override13 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 @Override11 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 @Override19 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窗口卖了一张票,剩余票数: 99Thread-1窗口卖了一张票,剩余票数: 97Thread-2窗口卖了一张票,剩余票数: 98Thread-2窗口卖了一张票,剩余票数: 96Thread-0窗口卖了一张票,剩余票数: 95Thread-1窗口卖了一张票,剩余票数: 94Thread-2窗口卖了一张票,剩余票数: 93Thread-0窗口卖了一张票,剩余票数: 91Thread-1窗口卖了一张票,剩余票数: 92Thread-0窗口卖了一张票,剩余票数: 90Thread-1窗口卖了一张票,剩余票数: 89Thread-2窗口卖了一张票,剩余票数: 88Thread-0窗口卖了一张票,剩余票数: 87Thread-1窗口卖了一张票,剩余票数: 86Thread-2窗口卖了一张票,剩余票数: 85Thread-0窗口卖了一张票,剩余票数: 84Thread-1窗口卖了一张票,剩余票数: 83Thread-2窗口卖了一张票,剩余票数: 82Thread-0窗口卖了一张票,剩余票数: 80Thread-1窗口卖了一张票,剩余票数: 81Thread-2窗口卖了一张票,剩余票数: 79Thread-0窗口卖了一张票,剩余票数: 77Thread-1窗口卖了一张票,剩余票数: 78Thread-2窗口卖了一张票,剩余票数: 76Thread-0窗口卖了一张票,剩余票数: 75Thread-1窗口卖了一张票,剩余票数: 75Thread-2窗口卖了一张票,剩余票数: 74Thread-1窗口卖了一张票,剩余票数: 73Thread-0窗口卖了一张票,剩余票数: 72Thread-2窗口卖了一张票,剩余票数: 71Thread-0窗口卖了一张票,剩余票数: 70Thread-1窗口卖了一张票,剩余票数: 69Thread-2窗口卖了一张票,剩余票数: 68Thread-1窗口卖了一张票,剩余票数: 67Thread-0窗口卖了一张票,剩余票数: 67Thread-2窗口卖了一张票,剩余票数: 66Thread-0窗口卖了一张票,剩余票数: 65Thread-1窗口卖了一张票,剩余票数: 65Thread-2窗口卖了一张票,剩余票数: 64Thread-1窗口卖了一张票,剩余票数: 63Thread-0窗口卖了一张票,剩余票数: 63Thread-2窗口卖了一张票,剩余票数: 62Thread-1窗口卖了一张票,剩余票数: 61Thread-0窗口卖了一张票,剩余票数: 61Thread-2窗口卖了一张票,剩余票数: 60Thread-0窗口卖了一张票,剩余票数: 59Thread-1窗口卖了一张票,剩余票数: 58Thread-2窗口卖了一张票,剩余票数: 57Thread-0窗口卖了一张票,剩余票数: 55Thread-1窗口卖了一张票,剩余票数: 56Thread-2窗口卖了一张票,剩余票数: 54Thread-0窗口卖了一张票,剩余票数: 53Thread-1窗口卖了一张票,剩余票数: 52Thread-2窗口卖了一张票,剩余票数: 51Thread-0窗口卖了一张票,剩余票数: 50Thread-1窗口卖了一张票,剩余票数: 50Thread-2窗口卖了一张票,剩余票数: 49Thread-1窗口卖了一张票,剩余票数: 48Thread-0窗口卖了一张票,剩余票数: 48Thread-2窗口卖了一张票,剩余票数: 47Thread-0窗口卖了一张票,剩余票数: 46Thread-1窗口卖了一张票,剩余票数: 46Thread-2窗口卖了一张票,剩余票数: 45Thread-0窗口卖了一张票,剩余票数: 43Thread-1窗口卖了一张票,剩余票数: 44Thread-2窗口卖了一张票,剩余票数: 42Thread-0窗口卖了一张票,剩余票数: 40Thread-1窗口卖了一张票,剩余票数: 41Thread-2窗口卖了一张票,剩余票数: 39Thread-1窗口卖了一张票,剩余票数: 38Thread-0窗口卖了一张票,剩余票数: 38Thread-2窗口卖了一张票,剩余票数: 37Thread-0窗口卖了一张票,剩余票数: 36Thread-1窗口卖了一张票,剩余票数: 35Thread-2窗口卖了一张票,剩余票数: 34Thread-1窗口卖了一张票,剩余票数: 33Thread-0窗口卖了一张票,剩余票数: 33Thread-2窗口卖了一张票,剩余票数: 32Thread-0窗口卖了一张票,剩余票数: 31Thread-1窗口卖了一张票,剩余票数: 31Thread-2窗口卖了一张票,剩余票数: 30Thread-1窗口卖了一张票,剩余票数: 29Thread-0窗口卖了一张票,剩余票数: 29Thread-2窗口卖了一张票,剩余票数: 28Thread-1窗口卖了一张票,剩余票数: 27Thread-0窗口卖了一张票,剩余票数: 27Thread-2窗口卖了一张票,剩余票数: 26Thread-0窗口卖了一张票,剩余票数: 24Thread-1窗口卖了一张票,剩余票数: 25Thread-2窗口卖了一张票,剩余票数: 23Thread-1窗口卖了一张票,剩余票数: 22Thread-0窗口卖了一张票,剩余票数: 21Thread-2窗口卖了一张票,剩余票数: 20Thread-1窗口卖了一张票,剩余票数: 19Thread-0窗口卖了一张票,剩余票数: 18Thread-2窗口卖了一张票,剩余票数: 17Thread-0窗口卖了一张票,剩余票数: 16Thread-1窗口卖了一张票,剩余票数: 15Thread-2窗口卖了一张票,剩余票数: 14Thread-1窗口卖了一张票,剩余票数: 13Thread-0窗口卖了一张票,剩余票数: 13Thread-2窗口卖了一张票,剩余票数: 12Thread-0窗口卖了一张票,剩余票数: 11Thread-1窗口卖了一张票,剩余票数: 10Thread-2窗口卖了一张票,剩余票数: 9Thread-1窗口卖了一张票,剩余票数: 8Thread-0窗口卖了一张票,剩余票数: 7Thread-2窗口卖了一张票,剩余票数: 6Thread-1窗口卖了一张票,剩余票数: 5Thread-0窗口卖了一张票,剩余票数: 4Thread-2窗口卖了一张票,剩余票数: 3Thread-1窗口卖了一张票,剩余票数: 2Thread-0窗口卖了一张票,剩余票数: 1Thread-2窗口卖了一张票,剩余票数: 0Thread-2窗口,票卖完了Thread-1窗口卖了一张票,剩余票数: -1Thread-0窗口卖了一张票,剩余票数: -1View 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窗口卖了一张票,剩余票数: 99Thread-2窗口卖了一张票,剩余票数: 98Thread-0窗口卖了一张票,剩余票数: 97Thread-1窗口卖了一张票,剩余票数: 95Thread-2窗口卖了一张票,剩余票数: 94Thread-0窗口卖了一张票,剩余票数: 96Thread-1窗口卖了一张票,剩余票数: 93Thread-1窗口卖了一张票,剩余票数: 92Thread-0窗口卖了一张票,剩余票数: 91Thread-2窗口卖了一张票,剩余票数: 90Thread-1窗口卖了一张票,剩余票数: 90Thread-2窗口卖了一张票,剩余票数: 89Thread-0窗口卖了一张票,剩余票数: 88Thread-1窗口卖了一张票,剩余票数: 87Thread-2窗口卖了一张票,剩余票数: 86Thread-1窗口卖了一张票,剩余票数: 85Thread-0窗口卖了一张票,剩余票数: 84Thread-1窗口卖了一张票,剩余票数: 83Thread-2窗口卖了一张票,剩余票数: 82Thread-0窗口卖了一张票,剩余票数: 81Thread-1窗口卖了一张票,剩余票数: 81Thread-2窗口卖了一张票,剩余票数: 80Thread-0窗口卖了一张票,剩余票数: 79Thread-2窗口卖了一张票,剩余票数: 78Thread-1窗口卖了一张票,剩余票数: 77Thread-0窗口卖了一张票,剩余票数: 76Thread-2窗口卖了一张票,剩余票数: 76Thread-1窗口卖了一张票,剩余票数: 75Thread-0窗口卖了一张票,剩余票数: 75Thread-2窗口卖了一张票,剩余票数: 74Thread-1窗口卖了一张票,剩余票数: 73Thread-0窗口卖了一张票,剩余票数: 72Thread-2窗口卖了一张票,剩余票数: 71Thread-0窗口卖了一张票,剩余票数: 70Thread-1窗口卖了一张票,剩余票数: 70Thread-2窗口卖了一张票,剩余票数: 69Thread-0窗口卖了一张票,剩余票数: 69Thread-2窗口卖了一张票,剩余票数: 68Thread-1窗口卖了一张票,剩余票数: 67Thread-0窗口卖了一张票,剩余票数: 66Thread-2窗口卖了一张票,剩余票数: 66Thread-1窗口卖了一张票,剩余票数: 65Thread-0窗口卖了一张票,剩余票数: 65Thread-1窗口卖了一张票,剩余票数: 64Thread-2窗口卖了一张票,剩余票数: 64Thread-0窗口卖了一张票,剩余票数: 63Thread-1窗口卖了一张票,剩余票数: 62Thread-2窗口卖了一张票,剩余票数: 61Thread-0窗口卖了一张票,剩余票数: 60Thread-2窗口卖了一张票,剩余票数: 59Thread-1窗口卖了一张票,剩余票数: 59Thread-2窗口卖了一张票,剩余票数: 58Thread-0窗口卖了一张票,剩余票数: 57Thread-0窗口卖了一张票,剩余票数: 56Thread-2窗口卖了一张票,剩余票数: 55Thread-1窗口卖了一张票,剩余票数: 54Thread-0窗口卖了一张票,剩余票数: 53Thread-2窗口卖了一张票,剩余票数: 52Thread-1窗口卖了一张票,剩余票数: 51Thread-0窗口卖了一张票,剩余票数: 50Thread-0窗口卖了一张票,剩余票数: 49Thread-1窗口卖了一张票,剩余票数: 48Thread-2窗口卖了一张票,剩余票数: 47Thread-2窗口卖了一张票,剩余票数: 46Thread-0窗口卖了一张票,剩余票数: 46Thread-2窗口卖了一张票,剩余票数: 45Thread-1窗口卖了一张票,剩余票数: 44Thread-0窗口卖了一张票,剩余票数: 43Thread-1窗口卖了一张票,剩余票数: 43Thread-2窗口卖了一张票,剩余票数: 42Thread-0窗口卖了一张票,剩余票数: 41Thread-1窗口卖了一张票,剩余票数: 40Thread-2窗口卖了一张票,剩余票数: 40Thread-1窗口卖了一张票,剩余票数: 39Thread-0窗口卖了一张票,剩余票数: 39Thread-2窗口卖了一张票,剩余票数: 38Thread-1窗口卖了一张票,剩余票数: 38Thread-0窗口卖了一张票,剩余票数: 37Thread-2窗口卖了一张票,剩余票数: 37Thread-1窗口卖了一张票,剩余票数: 36Thread-0窗口卖了一张票,剩余票数: 36Thread-1窗口卖了一张票,剩余票数: 35Thread-2窗口卖了一张票,剩余票数: 34Thread-0窗口卖了一张票,剩余票数: 32Thread-1窗口卖了一张票,剩余票数: 33Thread-1窗口卖了一张票,剩余票数: 31Thread-2窗口卖了一张票,剩余票数: 31Thread-1窗口卖了一张票,剩余票数: 30Thread-0窗口卖了一张票,剩余票数: 30Thread-1窗口卖了一张票,剩余票数: 29Thread-2窗口卖了一张票,剩余票数: 28Thread-1窗口卖了一张票,剩余票数: 27Thread-0窗口卖了一张票,剩余票数: 27Thread-1窗口卖了一张票,剩余票数: 26Thread-2窗口卖了一张票,剩余票数: 26Thread-1窗口卖了一张票,剩余票数: 25Thread-0窗口卖了一张票,剩余票数: 24Thread-2窗口卖了一张票,剩余票数: 23Thread-1窗口卖了一张票,剩余票数: 22Thread-2窗口卖了一张票,剩余票数: 21Thread-0窗口卖了一张票,剩余票数: 21Thread-1窗口卖了一张票,剩余票数: 20Thread-2窗口卖了一张票,剩余票数: 20Thread-0窗口卖了一张票,剩余票数: 19Thread-1窗口卖了一张票,剩余票数: 19Thread-1窗口卖了一张票,剩余票数: 18Thread-2窗口卖了一张票,剩余票数: 18Thread-0窗口卖了一张票,剩余票数: 17Thread-1窗口卖了一张票,剩余票数: 17Thread-2窗口卖了一张票,剩余票数: 16Thread-0窗口卖了一张票,剩余票数: 15Thread-1窗口卖了一张票,剩余票数: 14Thread-2窗口卖了一张票,剩余票数: 13Thread-0窗口卖了一张票,剩余票数: 12Thread-1窗口卖了一张票,剩余票数: 12Thread-2窗口卖了一张票,剩余票数: 11Thread-0窗口卖了一张票,剩余票数: 11Thread-1窗口卖了一张票,剩余票数: 10Thread-2窗口卖了一张票,剩余票数: 9Thread-1窗口卖了一张票,剩余票数: 8Thread-0窗口卖了一张票,剩余票数: 8Thread-1窗口卖了一张票,剩余票数: 7Thread-2窗口卖了一张票,剩余票数: 7Thread-0窗口卖了一张票,剩余票数: 6Thread-1窗口卖了一张票,剩余票数: 6Thread-2窗口卖了一张票,剩余票数: 5Thread-0窗口卖了一张票,剩余票数: 5Thread-2窗口卖了一张票,剩余票数: 4Thread-1窗口卖了一张票,剩余票数: 4Thread-0窗口卖了一张票,剩余票数: 3Thread-2窗口卖了一张票,剩余票数: 3Thread-0窗口卖了一张票,剩余票数: 2Thread-1窗口卖了一张票,剩余票数: 2Thread-1窗口卖了一张票,剩余票数: 1Thread-2窗口卖了一张票,剩余票数: 0Thread-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窗口卖了一张票,剩余票数: 99Thread-0窗口卖了一张票,剩余票数: 97Thread-2窗口卖了一张票,剩余票数: 98Thread-2窗口卖了一张票,剩余票数: 96Thread-0窗口卖了一张票,剩余票数: 95Thread-1窗口卖了一张票,剩余票数: 94Thread-2窗口卖了一张票,剩余票数: 93Thread-1窗口卖了一张票,剩余票数: 92Thread-0窗口卖了一张票,剩余票数: 91Thread-1窗口卖了一张票,剩余票数: 89Thread-2窗口卖了一张票,剩余票数: 90Thread-0窗口卖了一张票,剩余票数: 88Thread-0窗口卖了一张票,剩余票数: 87Thread-1窗口卖了一张票,剩余票数: 86Thread-2窗口卖了一张票,剩余票数: 85Thread-2窗口卖了一张票,剩余票数: 84Thread-1窗口卖了一张票,剩余票数: 83Thread-0窗口卖了一张票,剩余票数: 82Thread-2窗口卖了一张票,剩余票数: 81Thread-0窗口卖了一张票,剩余票数: 80Thread-1窗口卖了一张票,剩余票数: 79Thread-2窗口卖了一张票,剩余票数: 78Thread-1窗口卖了一张票,剩余票数: 77Thread-0窗口卖了一张票,剩余票数: 76Thread-1窗口卖了一张票,剩余票数: 75Thread-0窗口卖了一张票,剩余票数: 74Thread-2窗口卖了一张票,剩余票数: 73Thread-2窗口卖了一张票,剩余票数: 72Thread-1窗口卖了一张票,剩余票数: 72Thread-0窗口卖了一张票,剩余票数: 71Thread-2窗口卖了一张票,剩余票数: 70Thread-1窗口卖了一张票,剩余票数: 68Thread-0窗口卖了一张票,剩余票数: 69Thread-0窗口卖了一张票,剩余票数: 67Thread-1窗口卖了一张票,剩余票数: 66Thread-2窗口卖了一张票,剩余票数: 65Thread-1窗口卖了一张票,剩余票数: 64Thread-0窗口卖了一张票,剩余票数: 63Thread-2窗口卖了一张票,剩余票数: 62Thread-1窗口卖了一张票,剩余票数: 61Thread-0窗口卖了一张票,剩余票数: 61Thread-2窗口卖了一张票,剩余票数: 60Thread-1窗口卖了一张票,剩余票数: 59Thread-0窗口卖了一张票,剩余票数: 58Thread-2窗口卖了一张票,剩余票数: 57Thread-0窗口卖了一张票,剩余票数: 56Thread-1窗口卖了一张票,剩余票数: 56Thread-2窗口卖了一张票,剩余票数: 55Thread-1窗口卖了一张票,剩余票数: 53Thread-0窗口卖了一张票,剩余票数: 54Thread-2窗口卖了一张票,剩余票数: 52Thread-1窗口卖了一张票,剩余票数: 51Thread-0窗口卖了一张票,剩余票数: 51Thread-2窗口卖了一张票,剩余票数: 50Thread-0窗口卖了一张票,剩余票数: 48Thread-1窗口卖了一张票,剩余票数: 49Thread-2窗口卖了一张票,剩余票数: 47Thread-1窗口卖了一张票,剩余票数: 46Thread-0窗口卖了一张票,剩余票数: 45Thread-2窗口卖了一张票,剩余票数: 44Thread-0窗口卖了一张票,剩余票数: 43Thread-1窗口卖了一张票,剩余票数: 42Thread-2窗口卖了一张票,剩余票数: 41Thread-1窗口卖了一张票,剩余票数: 39Thread-0窗口卖了一张票,剩余票数: 40Thread-2窗口卖了一张票,剩余票数: 38Thread-1窗口卖了一张票,剩余票数: 37Thread-0窗口卖了一张票,剩余票数: 36Thread-2窗口卖了一张票,剩余票数: 35Thread-0窗口卖了一张票,剩余票数: 34Thread-1窗口卖了一张票,剩余票数: 33Thread-2窗口卖了一张票,剩余票数: 32Thread-0窗口卖了一张票,剩余票数: 31Thread-1窗口卖了一张票,剩余票数: 30Thread-2窗口卖了一张票,剩余票数: 29Thread-0窗口卖了一张票,剩余票数: 28Thread-1窗口卖了一张票,剩余票数: 28Thread-2窗口卖了一张票,剩余票数: 27Thread-1窗口卖了一张票,剩余票数: 26Thread-0窗口卖了一张票,剩余票数: 25Thread-2窗口卖了一张票,剩余票数: 24Thread-0窗口卖了一张票,剩余票数: 23Thread-1窗口卖了一张票,剩余票数: 23Thread-2窗口卖了一张票,剩余票数: 22Thread-1窗口卖了一张票,剩余票数: 21Thread-0窗口卖了一张票,剩余票数: 20Thread-2窗口卖了一张票,剩余票数: 19Thread-0窗口卖了一张票,剩余票数: 18Thread-1窗口卖了一张票,剩余票数: 17Thread-2窗口卖了一张票,剩余票数: 16Thread-1窗口卖了一张票,剩余票数: 15Thread-0窗口卖了一张票,剩余票数: 14Thread-2窗口卖了一张票,剩余票数: 13Thread-0窗口卖了一张票,剩余票数: 12Thread-1窗口卖了一张票,剩余票数: 11Thread-2窗口卖了一张票,剩余票数: 10Thread-0窗口卖了一张票,剩余票数: 9Thread-1窗口卖了一张票,剩余票数: 8Thread-2窗口卖了一张票,剩余票数: 7Thread-1窗口卖了一张票,剩余票数: 6Thread-0窗口卖了一张票,剩余票数: 6Thread-2窗口卖了一张票,剩余票数: 5Thread-1窗口卖了一张票,剩余票数: 3Thread-0窗口卖了一张票,剩余票数: 4Thread-2窗口卖了一张票,剩余票数: 2Thread-0窗口卖了一张票,剩余票数: 1Thread-0窗口,票卖完了Thread-1窗口卖了一张票,剩余票数: 0Thread-2窗口卖了一张票,剩余票数: -1Process finished with exit code 0View 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窗口卖了一张票,剩余票数: 99Thread-2窗口卖了一张票,剩余票数: 98Thread-2窗口卖了一张票,剩余票数: 97Thread-2窗口卖了一张票,剩余票数: 96Thread-2窗口卖了一张票,剩余票数: 95Thread-2窗口卖了一张票,剩余票数: 94Thread-2窗口卖了一张票,剩余票数: 93Thread-2窗口卖了一张票,剩余票数: 92Thread-2窗口卖了一张票,剩余票数: 91Thread-1窗口卖了一张票,剩余票数: 90Thread-0窗口卖了一张票,剩余票数: 89Thread-1窗口卖了一张票,剩余票数: 88Thread-1窗口卖了一张票,剩余票数: 87Thread-1窗口卖了一张票,剩余票数: 86Thread-2窗口卖了一张票,剩余票数: 85Thread-2窗口卖了一张票,剩余票数: 84Thread-2窗口卖了一张票,剩余票数: 83Thread-1窗口卖了一张票,剩余票数: 82Thread-1窗口卖了一张票,剩余票数: 81Thread-0窗口卖了一张票,剩余票数: 80Thread-0窗口卖了一张票,剩余票数: 79Thread-0窗口卖了一张票,剩余票数: 78Thread-0窗口卖了一张票,剩余票数: 77Thread-1窗口卖了一张票,剩余票数: 76Thread-2窗口卖了一张票,剩余票数: 75Thread-2窗口卖了一张票,剩余票数: 74Thread-2窗口卖了一张票,剩余票数: 73Thread-2窗口卖了一张票,剩余票数: 72Thread-2窗口卖了一张票,剩余票数: 71Thread-2窗口卖了一张票,剩余票数: 70Thread-1窗口卖了一张票,剩余票数: 69Thread-1窗口卖了一张票,剩余票数: 68Thread-1窗口卖了一张票,剩余票数: 67Thread-0窗口卖了一张票,剩余票数: 66Thread-0窗口卖了一张票,剩余票数: 65Thread-1窗口卖了一张票,剩余票数: 64Thread-2窗口卖了一张票,剩余票数: 63Thread-2窗口卖了一张票,剩余票数: 62Thread-2窗口卖了一张票,剩余票数: 61Thread-1窗口卖了一张票,剩余票数: 60Thread-1窗口卖了一张票,剩余票数: 59Thread-1窗口卖了一张票,剩余票数: 58Thread-1窗口卖了一张票,剩余票数: 57Thread-1窗口卖了一张票,剩余票数: 56Thread-1窗口卖了一张票,剩余票数: 55Thread-0窗口卖了一张票,剩余票数: 54Thread-1窗口卖了一张票,剩余票数: 53Thread-2窗口卖了一张票,剩余票数: 52Thread-2窗口卖了一张票,剩余票数: 51Thread-2窗口卖了一张票,剩余票数: 50Thread-2窗口卖了一张票,剩余票数: 49Thread-2窗口卖了一张票,剩余票数: 48Thread-2窗口卖了一张票,剩余票数: 47Thread-2窗口卖了一张票,剩余票数: 46Thread-2窗口卖了一张票,剩余票数: 45Thread-1窗口卖了一张票,剩余票数: 44Thread-1窗口卖了一张票,剩余票数: 43Thread-0窗口卖了一张票,剩余票数: 42Thread-1窗口卖了一张票,剩余票数: 41Thread-2窗口卖了一张票,剩余票数: 40Thread-2窗口卖了一张票,剩余票数: 39Thread-2窗口卖了一张票,剩余票数: 38Thread-2窗口卖了一张票,剩余票数: 37Thread-2窗口卖了一张票,剩余票数: 36Thread-2窗口卖了一张票,剩余票数: 35Thread-2窗口卖了一张票,剩余票数: 34Thread-2窗口卖了一张票,剩余票数: 33Thread-1窗口卖了一张票,剩余票数: 32Thread-0窗口卖了一张票,剩余票数: 31Thread-1窗口卖了一张票,剩余票数: 30Thread-1窗口卖了一张票,剩余票数: 29Thread-2窗口卖了一张票,剩余票数: 28Thread-2窗口卖了一张票,剩余票数: 27Thread-1窗口卖了一张票,剩余票数: 26Thread-1窗口卖了一张票,剩余票数: 25Thread-0窗口卖了一张票,剩余票数: 24Thread-1窗口卖了一张票,剩余票数: 23Thread-2窗口卖了一张票,剩余票数: 22Thread-1窗口卖了一张票,剩余票数: 21Thread-1窗口卖了一张票,剩余票数: 20Thread-0窗口卖了一张票,剩余票数: 19Thread-1窗口卖了一张票,剩余票数: 18Thread-1窗口卖了一张票,剩余票数: 17Thread-1窗口卖了一张票,剩余票数: 16Thread-1窗口卖了一张票,剩余票数: 15Thread-1窗口卖了一张票,剩余票数: 14Thread-2窗口卖了一张票,剩余票数: 13Thread-2窗口卖了一张票,剩余票数: 12Thread-2窗口卖了一张票,剩余票数: 11Thread-2窗口卖了一张票,剩余票数: 10Thread-2窗口卖了一张票,剩余票数: 9Thread-1窗口卖了一张票,剩余票数: 8Thread-0窗口卖了一张票,剩余票数: 7Thread-0窗口卖了一张票,剩余票数: 6Thread-1窗口卖了一张票,剩余票数: 5Thread-2窗口卖了一张票,剩余票数: 4Thread-2窗口卖了一张票,剩余票数: 3Thread-1窗口卖了一张票,剩余票数: 2Thread-0窗口卖了一张票,剩余票数: 1Thread-1窗口卖了一张票,剩余票数: 0Thread-1窗口,票卖完了Thread-2窗口,票卖完了Thread-0窗口,票卖完了View Code
可见运行结果完全正确。
关键词:
java中的多线程
2022 最新版 JDK 17 下载与安装 步骤演示 (图示版)
世界热讯:【验证码逆向专栏】某验四代滑块验证码逆向分析
世界讯息:Dubbo 3 端口协议复用
水里也能开!仰望U8核心系统支持IP68防水:可浮水行驶
百万级纯电性能超跑!比亚迪仰望U9来了:零百加速2秒级、电动蝴蝶门
对标比亚迪仰望U8 东风猛士M-Terrain官图发布:超级硬汉
时隔18年再出续篇!经典老片《神话》续集定名《传说》
144MB缓存性能无解!Zen4架构AMD锐龙9 7950X3D比酷睿i9-13900K快了52%
每日快看:浅谈多项式与生成函数
hive调优之参数设置
如何接入畅联云平台管理物联网设备?
【速看料】IM通讯协议专题学习(七):手把手教你如何在NodeJS中从零使用Protobuf
荣耀Magic 5系列镜头模组曝光:经典圆形设计、配100X长焦
每日观点:地表最快!realme宣布首发量产240W满级秒充:充满不到10分钟
李国庆称腾讯京东有大公司病 当当就是失败的案例
98年哥哥返乡给15个弟妹买一车礼物:塞满整个后备箱
荣耀MagicOS获新浪2022科技风云榜年度智能操作系统奖
统计B站番剧真实评分
基础可视化图表之分组条形图
锐龙9 6900HX加持!魔方M600迷你主机图赏
【世界报资讯】便宜还好用:绿联iPhone全系钢化膜冲量3.6元/张
世界速看:折叠屏我只认OPPO Find N2:安卓阵营独一无二
环球聚焦:宝马展示i Vision Dee概念汽车:可变换车身颜色 有科幻味了
全球视点!员工:不怕大家拿任何手机跟一加11比精致度和质感
天天消息!RHEL/CentOS yum 源问题
记 对接拼多多官方代报 辽宁电子口岸联达通客户端 ic卡加签版
天天视讯!透过现象看本质,我找到了Netty粘包与半包的这几种解决方案。
天天快资讯丨天府可乐因破产传闻销量暴增 民族品牌不会轻易垮:请理性消费
144MB暴力缓存!AMD锐龙7000 3D缓存版杀来:16核心神奇120W
马斯克最“惨” 福布斯:2022年美国亿万富翁身价创纪录暴跌
全球即时看!独立包装、现货速发:掌护快速检测试剂盒2.9元/份
世界微头条丨李斌发蔚来全员信:列举8大问题 有同行比我们更出色
全球热议:比亚迪宋PLUS上月热销50006台:接棒哈弗H6成新一代神车
环球速看:从菜鸟到团队协同大神:产品经理工具技能修炼
当前聚焦:DTALK直播预约 | 金融行业嘉宾分享:金融机构数据治理实践路径
视焦点讯!ZooKeeper 避坑实践:SnapCount 设置不合理导致磁盘爆满,服务不可用
一纸死亡威胁:让安卓最良心的PS2模拟器凉凉了
世界讯息:年底发福利 马自达推出全系购车优惠:CX-5置换1万补贴
环球头条:AMD正式发布锐龙7000三款新U:一键能效暴涨47%!就看价格了
微动态丨增程混动加持 Aska A5飞行汽车首发亮相:配降落伞、可垂直起降
最新资讯:AMD锐龙7000降临笔记本:4种CPU/3种GPU/4种工艺 性能最高提升78%!
环球热头条丨索尼《GT赛车》真人电影!《头号赛车手》先导预告发布:8月上映
全球动态:确定了!漫威新片《黑豹2》2月1号正式上线流媒体
不减薪、工作5小时下班!实探“四天半工作制”乐视:比预想的还好
天天新资讯:《阿凡达1/2》仅是开胃菜?卡梅隆:好戏在后面
当前视讯!元旦就“入夏”?极端暖冬席卷欧洲:至少7国破气温记录
快看点丨修改NuGet包默认存放位置
环球快消息!AcWing1174. 受欢迎的牛
当前信息:苹果砍单立讯精密最受伤?官方回应:与客户合作正常
环球热讯:iPhone 15 Pro/Ultra升级!钛合金边框+8GB内存
天天视讯!内存暴跌4成 现在不买待何时?
iPhone 14 Pro全天候显示屏有多费电?实测每小时不到1%
环球今热点:今日发布 比亚迪仰望首款硬派越野车内饰谍照:百万级豪华
『JNPF』低代码创新赋能数字经济建设
【环球新视野】iPhone一直收集用户数据!隐私捍卫者苹果被法国重罚:我们不服
微信红包升级!全新动态红包封面上线
司机免费代驾870公里送卡友回家 获5千元正能量奖金:这魄力网友点赞
天天快看点丨《阿凡达2》 已经被“烂片之王”翻拍了:豆瓣居然全5星
神U换代 AMD Zen4架构锐龙7 7800X3D来了:游戏性能提升30%
微信支付--JSAPI支付(微信小程序和微信公众号支付都可以采用该方式)
13+3相豪华供电!影驰RTX 4070 Ti星曜OC显卡图赏
女子跨年夜中1000万后悔跟孩子说 他们说不奋斗了引网友热议:这能躺平?
环球热议:乘联会:预计2022年乘用车销量2070万辆 今年或0增长
存款贬值了快一半 土耳其人把游戏当成了救命稻草
每周只上班4天半!乐视居然成了"反卷斗士":真是神仙日子吗?
一本通动态规划篇解题报告
当前视讯!Python的保留字、标识符、变量的定义、常用数据类型、数据类型转换
砍单三大产品线 苹果市值跌破2万亿美元 富士康表态
世界热点评!抄底吗?知名投资人段永平:已将手上腾讯美股换成苹果
天天观速讯丨二次元外观下带来澎湃性能!铭瑄MS RTX 4070 Ti OC12G璦珈评测:最强192bit显卡非它莫属
10升好身材!ROG发布冰刃X迷你机:居然有没发布的RTX 4070
金庸最成功的作品 来源自历史上让人耻辱的失败
焦点要闻:500吨级!中国最强液体火箭发动机的“家”快建好了
世界信息:CF13C. Sequence
看点:设计模式简单介绍
胡伟武:Linux桌面软件生态是x86和ARM“软肋” 龙芯希望一两年后全面超过
丰田总裁再度质疑电动汽车:这会让车企降低价值!
每日资讯:RTX 4090加持:ROG发布新款XG Mobile显卡坞
即时:三星发布全球首款8K 150寸投影仪:离墙几毫米即可完成投射
焦点热文:画面太美!男子意外发现交通卡余额有172万 官方回应真相无奈
天天速看:写给大忙人看的Go语言快速指南(中文翻译)
天天实时:[概率论与数理统计]笔记:2.2 随机变量的数字特征
Python:numpy模块最详细的教程
python3实现字符串的全排列的方法(无重复字符)两种解决方法
全球快播:python中可以处理word文档的模块:docx模块
环球即时看!宏碁发布eKinekt BD 3酷骑桌:工作之余还能骑动感单车
世界热讯:1.6亿美元是罚定了!印度法庭驳回谷歌推翻垄断案的请求
当前热点-17万元起真香!奇瑞最高颜值SUV星途瑶光盲订量已达6012台
环球热点评!2022广州车展压轴登场 这八款新能源新车千万不要错过
今头条!全新NT架构加持!腾讯QQ原生上架麒麟应用商店
天天微资讯!国产可乐为什么都在陆续消失?专家道出原因
哄娃神器 一公司推出可自动驾驶婴儿车:售价约2.2万人民币
画风有《魔兽》那味了:国产多端MMO《塔瑞斯世界》PV首曝
【环球热闻】男子一口气网购20个26元扫地机器人:场面壮观实测失望
男子为研究显卡到网吧一口气拿7块:网友调侃要都是4090赚大
环球微资讯!Float value issue in GLSL
【环球热闻】事件总线 + 函数计算构建云上最佳事件驱动架构应用
实时:C罗说世界杯唯一赢阿根廷的是沙特 这里是新挑战 不是养老
配大哥H9同款2.0T 国产豪华轿跑红旗H6官图发布:罕见中置双排气