一. 线程的创建
线程的创建方式有两种:
一种是继承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
可见运行结果完全正确。