java_线程

一、线程相关概念

(一)程序

在这里插入图片描述

(二)进程

在这里插入图片描述
在这里插入图片描述

(三)线程

在这里插入图片描述

(四)其他相关概念

在这里插入图片描述
在这里插入图片描述

		Runtime runtime = Runtime.getRuntime();
        //获取当前电脑cpu数量
        int cpuNums = runtime.availableProcessors();
        System.out.println("cpuNums" + cpuNums);

二、线程基本使用

(一)创建线程的两种方式

这里是引用
在这里插入图片描述

(二)线程应用案例1-继承Thread类

在这里插入图片描述
要等所有线程执行完毕才会退出
在这里插入图片描述
在多线程里面,主线程结束,子线程还没结束这是可以的
要所有的线程都结束了,然后进程才结束,然后退出程序

public class Thread01 {
    public static void main(String[] args) throws InterruptedException{
        //演示通过Thread类创建线程
        //创建Cat对象,可以当做线程
        Cat cat = new Cat();
        //cat.start();//启动线程
        cat.run();//run方法就是一个普通的方法,并没有启动线程,就会把run方法执行完毕,才会向下执行
        
        //说明:main线程启动一个子线程 Tread-0,主线程不会阻塞,会继续执行
        //这时,主线程和子线程交替执行
        System.out.println("主线程继续执行" + Thread.currentThread().getName());//主线程名称
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程 i=" + i);
            //让主线程休眠
            Thread.sleep(1000);
        }
    }
}
//1.当一个类继承了Thread 类,该类就可以当成线程使用
//2.我们会重写run方法,写上自己的业务代码
//3.run Thread 类,实现了Runnable 接口的run方法
class Cat extends Thread {
    int times = 0;
    @Override
    public void run() {//重写run方法,写上自己的逻辑
        while(true) {
            //该线程每隔1秒,在控制台输出“喵喵,我是小猫咪“
            System.out.println("喵喵,我是小猫咪" + (++times) + Thread.currentThread().getName());
            //快捷键 ctrl+alt+t
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(times == 8) {
                break;//当times等于8,退出,线程也退出
            }
        }
    }
}

总结:
为什么是start?

调用cat.start()才会真正启动线程,所有线程执行完毕才结束程序
调用cat.run()不会真正启动线程,线程名称是main

在这里插入图片描述
在这里插入图片描述

(三)线程应用案例2-实现Runnable接口

这里是引用
在这里插入图片描述

package com.hapedu;

public class Thread02 {
    public static void main(String[] args) {
//        Dog dog = new Dog();
//        //dog.start();这里不能调用start
//
//        //创建Thread对象,把dog对象(实现Runnable),放入Thread
//        Thread thread = new Thread(dog);
//        thread.start();

        Tiger tiger = new Tiger();
        ThreadProxy threadProxy = new ThreadProxy(tiger);

    }
}

class Animal {}
class Tiger extends Animal implements Runnable {
    @Override
    public void run() {
        System.out.println("老虎嗷嗷叫");
    }
}

class ThreadProxy implements Runnable {

    private Runnable target = null;//属性,类型是Runnable


    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

    public ThreadProxy(Runnable target) {
        this.target = target;
    }
    public void start() {
        start0();
    }
    public void start0() {
        run();
    }
}

class Dog implements Runnable {//通过实现Runnable接口,开发线程

    int count = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("小狗汪汪叫" + (++count) + Thread.currentThread().getName());
            //休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) {
                break;
            }
        }
    }
}

(四)线程使用应用案例-多线程执行

这里是引用

package com.hapedu;

public class Thread03 {
    public static void main(String[] args) {

        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();
        thread2.start();
    }
}
class T1 implements Runnable {
    int count = 0;
    @Override
    public void run() {
        while (true) {
            //每隔1秒输出“hello,world”,输出10次
            System.out.println("hello,world " + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) {
                break;
            }
        }

    }
}
class T2 implements Runnable {
    int count = 0;
    @Override
    public void run() {
        while (true) {
            //每隔1秒输出“hello,world”,输出10次
            System.out.println("hi " + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 5) {
                break;
            }
        }

    }
}

(五)继承Thread VS 实现Runnable的区别

这里是引用
在这里插入图片描述

package com.hapedu.ticket;

public class SellTicket {
    public static void main(String[] args) {
//        SellTicket01 sellTicket01 = new SellTicket01();
//        SellTicket01 sellTicket02 = new SellTicket01();
//        SellTicket01 sellTicket03 = new SellTicket01();
//
//        //出现票数超卖
//        sellTicket01.start();//启动售票线程
//        sellTicket02.start();//启动售票线程
//        sellTicket03.start();//启动售票线程

        System.out.println("===使用实现接口方式类售票===");
        SellTicket02 sellTicket02 = new SellTicket02();

        new Thread(sellTicket02).start();//第1个线程-窗口
        new Thread(sellTicket02).start();//第2个线程-窗口
        new Thread(sellTicket02).start();//第3个线程-窗口
    }
}
//使用Thread方式
class SellTicket01 extends Thread {

    private static int ticketNum = 100;//让多个线程共享

    @Override
    public void run() {
        while(true) {
            if(ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }
            //休眠50毫秒
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
             + " 剩余票数=" + (--ticketNum));
        }
    }
}

//实现接口方式
class SellTicket02 implements Runnable {
    private int ticketNum = 100;//让多个线程贡献ticketNum

    @Override
    public void run() {
        while(true) {
            if(ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }
            //休眠50毫秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));
        }
    }
}

三、线程终止

(一)基本说明

在这里插入图片描述

package com.hapedu.exit_;

public class ThreadExit_ {
    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        t1.start();

        //如果希望main线程去控制t1 线程的终止,必须可以修改
        //让t1 退出run方法,从而终止t1 线程->通知方式

        //让主线程休眠10秒,再通知t1线程退出
        System.out.println("main线程休眠10秒");
        Thread.sleep(10 * 1000);//alt+enter
        t1.setLoop(false);
    }
}

class T extends Thread {
    int count = 0;
    //设置一个控制变量
    private boolean loop = true;
    @Override
    public void run() {
        while (loop) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("T 线程还在运行" + (++count));
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

四、线程常用方法

(一)常用方法第一组

这里是引用

package com.hapedu.exit_;

public class ThreadMethod01 {
    public static void main(String[] args) throws InterruptedException {
        T1 t1 = new T1();
        t1.setName("老韩");
        t1.setPriority(Thread.MIN_PRIORITY);
        t1.start();//启动子线程

        //主线程打印5个hi,就中断子线程的休眠
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("hi" + i);
        }
        System.out.println(t1.getName() + " 线程的有线程" + t1.getPriority());//1
        t1.interrupt();//当执行到这里,就会中断 t线程的休眠
    }
}
class T1 extends Thread {//自定义线程类
    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " 吃包子~~~" + i);
            }
            try {
                System.out.println(Thread.currentThread().getName() + " 休眠中~~~");
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                //当该线程执行到一个interrupt 方法时,就会catch一个异常,可以加入自己的业务代码
                //InterruptedException捕获到一个中断异常
                System.out.println(Thread.currentThread().getName() + " 被 interrupt了");
            }
        }
    }
}

(二)注意事项和细节

在这里插入图片描述

(三)常用方法第二组

在这里插入图片描述

package com.hapedu.method;

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        T2 t2 = new T2();
        t2.start();
        for (int i = 1; i <=20; i++) {
            Thread.sleep(1000);
            System.out.println("主线程(小弟) 吃了" + i + " 包子");
            if (i == 5) {
                System.out.println("主线程(小弟) 让 子线程(老大)先吃");
                //join 线程插队,一定成功
                // t2.join();//这里相当于让t2线程先执行完毕
                Thread.yield();
                System.out.println("子线程(老大), 主线程(小弟) 接着吃。。");
            }
        }

    }
}
class T2 extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程(老大) 吃了 " + i + " 个包子");
        }

    }
}

(四)课堂练习

在这里插入图片描述

package com.hapedu.exercise;

public class ThreadMethodExercise {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new T());
        for (int i = 1; i <= 10; i++) {
            System.out.println("hi " + i);
            if( i == 5) {
                t.start();
                t.join();
            }
            Thread.sleep(1000);
        }
    }
}
class T implements Runnable {
    private int count = 0;
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程hello" + (++count));
            if (count == 10) {
                break;
            }
        }
    }
}

(五)用户线程和守护线程

在这里插入图片描述

package com.hapedu.exercise;

public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();//守护进程
        // 如果我们希望当main线程结束后, 子线程自动结束
        //只需要子线程设为守护线程即可
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();


        for (int i = 1; i <= 10; i++) {
            System.out.println("主线程.......");
            Thread.sleep(1000);
        }
    }
}

class MyDaemonThread extends Thread {
    public void run() {
        for (;;) {//无限循环
            try {
                Thread.sleep(50);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程");
        }
    }
}

五、线程的生命周期

(一)JDK总用Thread.State枚举表示了线程的几种状态

在这里插入图片描述
在这里插入图片描述

package com.hapedu.state;

public class ThreadState_ {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        System.out.println(t.getName() + " 状态 " + t.getState());
        t.start();
        while (Thread.State.TERMINATED != t.getState()) {
            System.out.println(t.getName() + " 状态 " + t.getState());
            Thread.sleep(1000);
        }
        System.out.println(t.getName() + " 状态 " +t.getState());
    }
}
class T extends Thread {
    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 10; i++) {
                System.out.println("hi" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            break;
        }
    }
}

六、线程的同步

(一)线程同步的机制

在这里插入图片描述

(二)同步具体方法-Synchronized

在这里插入图片描述

package com.hapedu.syn;

public class SellTicket {
    public static void main(String[] args) {
//        SellTicket01 sellTicket01 = new SellTicket01();
//        SellTicket01 sellTicket02 = new SellTicket01();
//        SellTicket01 sellTicket03 = new SellTicket01();
//
//        //出现票数超卖
//        sellTicket01.start();//启动售票线程
//        sellTicket02.start();//启动售票线程
//        sellTicket03.start();//启动售票线程

//        System.out.println("===使用实现接口方式类售票===");
//        SellTicket02 sellTicket02 = new SellTicket02();
//
//        new Thread(sellTicket02).start();//第1个线程-窗口
//        new Thread(sellTicket02).start();//第2个线程-窗口
//        new Thread(sellTicket02).start();//第3个线程-窗口

        //测试一把
        SellTicket03 sellTicket03 = new SellTicket03();
        new Thread(sellTicket03).start();//第1个线程-窗口
        new Thread(sellTicket03).start();//第2个线程-窗口
        new Thread(sellTicket03).start();//第3个线程-窗口

    }
}

//实现接口方式,使用Synchronized线程同步
class SellTicket03 implements Runnable {
    private int ticketNum = 100;//让多个线程贡献ticketNum
    private boolean loop = true;//控制run变量
    public synchronized void sell() {//用的是同步方法,在同一时刻,只能有一个线程操作来执行sell方法

        if(ticketNum <= 0) {
            System.out.println("售票结束...");
            loop = false;
            return;
        }
        //休眠50毫秒
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                + " 剩余票数=" + (--ticketNum));
    }

    @Override
    public void run() {//用的是同步方法,在同一时刻,只能有一个线程操作来执行run方法
        while(loop) {
            sell();
        }
    }
}

(三)分析同步原理

在这里插入图片描述

七、互斥锁

(一)基本介绍

在这里插入图片描述

(二)使用互斥锁synchronized来解决售票问题

package com.hapedu.syn;

public class SellTicket {
    public static void main(String[] args) {

        //测试一把
        SellTicket03 sellTicket03 = new SellTicket03();
        new Thread(sellTicket03).start();//第1个线程-窗口
        new Thread(sellTicket03).start();//第2个线程-窗口
        new Thread(sellTicket03).start();//第3个线程-窗口

    }
}

//实现接口方式,使用Synchronized线程同步
class SellTicket03 implements Runnable {
    private int ticketNum = 100;//让多个线程贡献ticketNum
    private boolean loop = true;//控制run变量
    Object object = new Object();

    //同步方法(静态的)的锁为当前类本身
    //1.public synchronized static void m1() {} 锁是加在SellTicket03.class
    //2.如果在静态方法中,实现一个同步代码块
    public synchronized static void m1() {}
    public static void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }



    //1.public synchronized void sell() {}//用的是同步方法
    //2.这是锁在 this 对象
    //3.也可以在代码块上写synchronized ,同步代码块

    public  void sell() {
        synchronized (/*this*/object) {//代码块
            if(ticketNum <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }
            //休眠50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));
        }

    }

    @Override
    public void run() {//用的是同步方法,在同一时刻,只能有一个线程操作来执行run方法
        while(loop) {
            sell();
        }
    }
}


(三)注意事项和细节

在这里插入图片描述

八、线程的死锁

(一)基本介绍

在这里插入图片描述

package com.hapedu.syn;

import java.util.TreeMap;

public class DeadLock_ {
    public static void main(String[] args) {
        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("A线程");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B线程");
        A.start();
        B.start();
    }
}
//线程
class DeadLockDemo extends Thread {
    static Object o1 = new Object();//保证多线程,共享一个对象,这里使用static
    static Object o2 = new Object();
    boolean flag;

    public DeadLockDemo(boolean flag) {//构造器
        this.flag = flag;
    }
    @Override
    public void run() {

        //下面业务逻辑的分析
        //1.如果flag 为True ,线程A就会持有o1对象锁,然后尝试去获取o2对象锁
        //2.如果线程A得不到o2对象锁,就会Blocked
        //3.如果flag 为false ,线程B就会先得到o2对象锁(else)然后尝试去获取o1对象锁
        //4.如果线程B得不到o1对象锁,就会Blocked
        if (flag) {
            synchronized (o1) {//对象互斥锁,下面就是同步代码
                System.out.println(Thread.currentThread().getName() + "进入1");
                synchronized (o2) {//这里获取li对象的监视仪
                    System.out.println(Thread.currentThread().getName() + "进入2");
                }
            }
        } else {
            synchronized (o2) {
            System.out.println(Thread.currentThread().getName() + "进入3");
            synchronized (o1) {//这里获取li对象的监视仪
                System.out.println(Thread.currentThread().getName() + "进入4");
            }
        }
    }}
}

九、释放锁

(一)下面操作会释放锁

在这里插入图片描述

(二)下面操作不会释放锁

在这里插入图片描述

十、本章作业

(一)编程题

在这里插入图片描述
在这里插入图片描述

package com.hapedu.homework;


import java.util.Scanner;

public class Homework01 {

    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);
        a.start();
        b.start();
    }
}
class A extends Thread {
    private boolean loop =true;
    @Override
    public void run() {
        while (loop) {
            System.out.println((int)(Math.random()*100 + 1));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}
class B extends Thread {
    private A a;
    private Scanner scanner = new Scanner(System.in);

    public B(A a) {//构造器中,直接传入A对象
        this.a = a;
    }

    @Override
    public void run() {
        while (true) {
        //接受用户的输入
        System.out.println("请输入你的指令");
        char key = scanner.next().toUpperCase().charAt(0);
        if(key == 'Q') {
            //以通知的方式q结束A线程
            a.setLoop(false);
            System.out.println("B线程退出.");
            break;
        }
    }

    }
}

在这里插入图片描述
在这里插入图片描述

package com.hapedu.homework;

public class Homework02 {
    public static void main(String[] args) {
        T t = new T();
        Thread thread1 = new Thread(t);
        thread1.setName("t1");
        Thread thread2 = new Thread(t);
        thread2.setName("t2");
        thread1.start();
        thread2.start();

    }
}
//编程取款的线程
//1.因为这里涉及到多个线程共享资源,所以我们使用实现Runnable方式
class T implements Runnable {
    private int money = 10000;

    @Override
    public void run() {
        while (true) {

            //1.这里使用了synchronized 实现了线程同步
            //2.当多个线程执行到这里时,就会去争夺this对象锁
            //3.哪个线程争取到this对象,就执行synchronized代码块,执行完,就会释放this对象锁
            //4.争夺不到this对象锁,就blocked,准备继续争夺
            //5.this对象锁是非公平锁

            synchronized (this) {
                //判断余额是否够
                if (money < 1000) {
                    System.out.println("余额不足");
                    break;
                }
                money -= 1000;
                System.out.println(Thread.currentThread().getName() + " 取出了1000块 " + "当前余额" + money);
            }
            //休眠1s
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值