最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

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窗口卖了一张票,剩余票数: -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窗口卖了一张票,剩余票数: 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 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窗口卖了一张票,剩余票数: 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

可见运行结果完全正确。

关键词: