多线程

创建线程

  • 继承Thread类创建线程
public class Thread01 {
    public static void main(String[] args) {
        //创建Cat对象,可以当做线程使用
        Cat cat = new Cat();
        //启动线程
        cat.start();
    }
}
//当一个类继承了Thread类,改类就可以做线程使用
class Cat extends Thread{
    @Override
    public void run() {
        System.out.println("喵喵喵");
    }
}
  • 实现Runable接口
public class Thread02 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        //将实现Runnable接口的类放入Thread(使用了代理模式)
        Thread t = new Thread(cat);
        t.start();
    }
}

//实现Runnable接口
class Cat implements Runnable{
    public void run() {
        System.out.println("喵喵喵");
    }
}
  • 多线程卖票实例
public class SellTicket{
    public static void main(String[] args) {
        //创建三个线程
        SellTicket01 thread01 = new SellTicket01();
        SellTicket01 thread02 = new SellTicket01();
        SellTicket01 thread03 = new SellTicket01();

        //启动三个线程
        thread01.start();
        thread02.start();
        thread03.start();
    }
}

class SellTicket01 extends  Thread{
    //票数
    private static int ticketNum = 100;

    @Override
    public void run() {
        while (true){
            if (ticketNum <= 0){
                System.out.println("售票结束");
                break;
            }

            //休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 "+Thread.currentThread().getName()+" 售出一张票,剩余票数 "+ (--ticketNum));
        }
    }
}
  • 存在问题,票数超卖问题(未加锁)

通知线程退出

public class Thread03 {
    public static void main(String[] args) throws Exception {
        Cat cat = new Cat();
        cat.start();
        Thread.sleep(1000);
        //通知线程,通过设置Cat对象flog通知线程停止
        cat.setFlog(false);
    }
}

class Cat extends Thread{
    
    private boolean flog = true;
    
    public void setFlog(boolean flog) {
        this.flog=flog;
    }
    @Override
    public void run() {
        while (flog){
            System.out.println("喵喵喵");
        }
    }
}

线程插队

  • yield:线程的让步。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定让步成功
  • join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有任务

  • 案例
    • 主线程创建一个子线程,每隔1s输入hello,输出10次,主线程每个1s输出hi,输出10次
    • 两个线程同时进行,当主线程输出5次后,就让子线程运行完毕,主线程再继续
public class Thread04 {
    public static void main(String[] args) throws Exception {
        //子线程打印10次hello
        T t = new T();
        t.start();

        //主线程打印10次hi
        for (int i =0;i<=10;i++){
            Thread.sleep(1000);
            System.out.println("hi " + i);

            //当打印了5次时让子线程运行完毕,主线程再继续(子线程t插队)
            if (i == 5){
                t.join();
            }
        }
    }
}

class T extends Thread{
    @Override
    public void run() {
        for (int i=1;i<=10;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("hello " + i);
        }
    }
}

线程同步机制

  • 同步方法
public class SellTicket{
    public static void main(String[] args) {
        //创建三个线程
        SellTicket01 thread01 = new SellTicket01();

        new Thread(thread01).start();
        new Thread(thread01).start();
        new Thread(thread01).start();
    }
}

class SellTicket01 implements Runnable{
    //票数
    private static int ticketNum = 10;

    private boolean loop = true;

    public  void run() {
        while (true){
            sell();
            if (!loop){
                break;
            }
        }
    }
    public synchronized void sell(){
            if (ticketNum <= 0){
                System.out.println("售票结束");
                loop = false;
                return;
            }
            //休眠50ms
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 "+Thread.currentThread().getName()+" 售出一张票,剩余票数 "+ (--ticketNum));
    }
}
  • 同步代码块
public class SellTicket{
    public static void main(String[] args) {
        SellTicket02 thread01 = new SellTicket02();
        SellTicket02 thread02 = new SellTicket02();
        SellTicket02 thread03 = new SellTicket02();

        thread01.start();
        thread02.start();
        thread03.start();
    }
}

class SellTicket02 extends Thread{
    //票数
    private static int ticketNum = 10;

    private boolean loop = true;

    @Override
    public  void run() {
        while (true){
            synchronized (Object.class){
                if (ticketNum <= 0){
                    System.out.println("售票结束");
                    loop = false;
                    return;
                }
                //休眠50ms
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("窗口 "+Thread.currentThread().getName()+" 售出一张票,剩余票数 "+ (--ticketNum));
            }
        }
    }
}
  • 互斥锁
    • Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
    • 每个对象都对于一个可称为“互斥锁”的标记,这个标记用来保证在任意时刻只能有一个线程访问该对象
    • 关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任意时候只能由一个线程访问
    • 同步的局限性:导致程序的执行效率要降低
    • 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一对象)
    • 同步方法(静态的)的锁为当前类本身
posted @ 2022-10-11 22:50  youmo~  阅读(21)  评论(0编辑  收藏  举报