线程和锁(基础)

程序(program)

在这里插入图片描述

进程

在这里插入图片描述

线程

在这里插入图片描述

java程序来显示电脑有多少个CPU

package 绘图;
/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-24
 * @Description: no
 * @Version: 1.0
 */
public class demo02 {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        //获取当前电脑cpu数量
        System.out.println(runtime.availableProcessors());  //16
    }
}

线程基本使用

在这里插入图片描述

简单案例

在这里插入图片描述

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-24
 * @Description: no
 * @Version: 1.0
 */

public class demo01 {
    public static void main(String[] args) throws Exception {
        //创建Cat对象,可以当作线程使用
        Cat cat = new Cat();
        cat.start();// 启动线程------》最终会执行cat的run方法
//        cat.run(); 如果直接这样写,就是一个普通的方法,线程名字还是main,并没有真正启动一个线程,就会把run方法执行完毕,才向下执行
        //当main线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行。
        //底层机制
//        public void start() {
//            synchronized (this) {
//                // zero status corresponds to state "NEW".
//                if (holder.threadStatus != 0)
//                    throw new IllegalThreadStateException();
//                start0();
//            }
//        start0()是本地方法,是JVM调用,底层是c/c++实现

            System.out.println("主线程继续执行"+Thread.currentThread().getName());  //main
        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{
    @Override
    public void run() {
        int times = 0;//重写run方法,写上自己的业务逻辑
        while (true) {
//        该线程每隔1秒,在控制台输出“爱你哦,小韩!”
            System.out.println("爱你哦,小韩!"+(++times)+"线程名="+Thread.currentThread().getName());
//        让该线程休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (times == 8) {   //线程退出
                break;
            }
        }
    }
}

在这里插入图片描述

Runnable创建线程

在这里插入图片描述

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-24
 * @Description: 通过实现接口Runnable来开发线程
 * @Version: 1.0
 */

public class demo02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
//        dog.start();   //错误,没有该方法
        //创建了Thread对象,把dog对象(实现了Runnable接口),放入
        //这里使用了静态代理的设计模式
        Thread thread = new Thread(dog);
        thread.start();
    }
}
class Dog implements Runnable{  //通过实现Runnable 接口来开发线程
    int count = 0;
    @Override
    public void run() {
        while(true){
            System.out.println("小狗汪汪叫"+(++count)+Thread.currentThread().getName());
            //休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(count == 10){
                break;
            }
        }
    }
}

看一个线程代理类,来模拟一个极简的Thread类

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-24
 * @Description: 通过实现接口Runnable来开发线程
 * @Version: 1.0
 */

public class demo02 {
    public static void main(String[] args) {
        Tiger tiger = new Tiger();  //实现了Runnbale
        ThreadProxy threadProxy = new ThreadProxy(tiger);
        threadProxy.start();
        //控制台输出:老虎嗷嗷叫!
    }
}
class Animal{}
class Tiger extends Animal implements Runnable{
    @Override
    public void run() {
        System.out.println("老虎嗷嗷叫!");
    }
}
//线程代理类,模拟了一个极简的Thread类
class ThreadProxy implements Runnable {
    private Runnable target = null;
    @Override
    public void run() {
        if (target != null) {
            target.run();  //动态绑定  运行类型是传进来的Tiger
        }
    }

    public ThreadProxy(Runnable target) {   //一般将实现了runnable接口的线程类传给 target,通过构造器传过去的,然后其它主要特点就是动态绑定了
        this.target = target;
    }
    public void start(){
        start0();
    }
    public void start0(){
        run();
    }
}

多线程

在这里插入图片描述

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: main线程启动两个子线程
 * @Version: 1.0
 */

public class demo03 {
    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) {
            System.out.println("hello word " + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 50) {
                break;
            }
        }
    }
}
class T2 implements Runnable{
    int count = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("hi " + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 60) {
                break;
            }
        }
    }
}

在这里插入图片描述

继承Thread vs实现Runnable的区别

在这里插入图片描述

线程终止

基本说明

  1. 当线程完成任务后,会自动退出
  2. 还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

简单案例

要求在main线程中去终止线程t

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo06 {
    public static void main(String[] args) {
        T t = new T();
        t.start();
        //如果需要main线程,控制T1线程的终止,只需修改loop
        //让t1 退出run方法,从而终止t1线程--->通知方式
        try {
            System.out.println("主线程休眠10秒");
            Thread.sleep(10000);   //主线程休眠10秒
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        t.setLoop(false);
    }
}
class T extends Thread {
   private int count = 0;
   private boolean loop = true;   //设置控制变量
    @Override
    public void run() {
        while (loop) {
            try {
                Thread.sleep(50);  //50ms
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("T 运行中"+(++count));
        }
    }

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

在这里插入图片描述

线程常用方法

在这里插入图片描述

注意事项和细节

在这里插入图片描述

简单案例

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo07 {
    public static void main(String[] args) throws Exception {
        T12 t12 = new T12();
        t12.setName("老韩");  //给线程设置名字
        t12.setPriority(Thread.MAX_PRIORITY);  //设置线程为最小优先级
        t12.start();

        //让主线程打印5 hi,然后我就中断子线程的休眠
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("hi"+i);
        }
        System.out.println(t12.getName()+"线程的优先级="+t12.getPriority());
        t12.interrupt();  //中断    当执行到这里,就会中断t线程的休眠
    }
}
class T12 extends Thread {  //自定义线程类
    @Override
    public void run() {
        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 一个异常,可以加入自己的业务代码
            System.out.println(Thread.currentThread().getName()+"被interrupt了");

        }
    }
}

在这里插入图片描述

join()和yield()方法

在这里插入图片描述

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo07 {
    public static void main(String[] args) throws Exception {
        T12 t12 = new T12();

        t12.start();
        for (int i = 0; i < 20; i++) {
            Thread.sleep(1000);
            System.out.println("主线程吃了"+i+"个包子");
            if(i == 5){
                System.out.println("主线程让子线程先吃");
                //线程插队
//                t12.join();  //相当于当让t2先执行完毕
                Thread.yield();  //主线程礼让    包子资源丰富,资源不紧缺,礼让不成功
                System.out.println("子线程吃完,主线程接着吃");
            }
        }
    }
}
class T12 extends Thread {  //自定义线程类
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("子线程吃了"+i+"个包子");
        }
        }
    }

在这里插入图片描述

用户线程和守护线程

  1. 用户线程

    也叫做工作线程,当线程的任务执行完或通知方式结束

  2. 守护线程:一般是为了工作线程服务的,当所有的用户线程结束,守护线程自动结束

  3. 常见的守护线程:垃圾回收机制

如何将一个线程设置成守护线程

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo09 {
    public static void main(String[] args)  throws Exception {
        MyDaemon myDaemon = new MyDaemon();
        //我们希望主线程结束,子线程自动退出,只需将子线程设置为守护线程
        myDaemon.setDaemon(true);  //先设置,再启动
        myDaemon.start();
        for (int i = 1; i <= 10; i++) {
            System.out.println("宝强在辛苦工作。。。");
            Thread.sleep(1000);
        }
    }
}
class MyDaemon extends Thread {
    @Override
    public void run() {
        for(;;){
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            System.out.println("马蓉和宋哲在愉快的聊天......");
        }
    }
}

线程的生命周期

JDK 中用 Thread.State 枚举表示了线程的几种状态

在这里插入图片描述

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo10 {
    public static void main(String[] args) throws Exception {
        T10 t10 = new T10();
        System.out.println(t10.getName() + "状态" + t10.getState());
        t10.start();
        while (Thread.State.TERMINATED != t10.getState()) {   //只要线程还没终止,就打印出线程目前的状态
            System.out.println(t10.getName() + "状态" + t10.getState() );
            Thread.sleep(1000);
        }
        System.out.println(t10.getName() + "状态" + t10.getState());
    }
}
class T10 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) {
                    throw new RuntimeException(e);
                }
            }
            break;
        }
    }
}


在这里插入图片描述

线程同步机制(Synchronized)

在这里插入图片描述

案例:三个窗口,出售100张票

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo05 {
    public static void main(String[] args) {
        SellTickets3 sellTicket = new SellTickets3();
        Thread thread1 = new Thread(sellTicket);
        Thread thread2 = new Thread(sellTicket);
        Thread thread3 = new Thread(sellTicket);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class SellTickets3 implements Runnable{
    private  int tickes = 100;   //多个线程共享tickes
    private boolean loop  =true;
    public synchronized void sell(){ 同步方法,在同一时刻,只能有一个线程来执行m方法
        if (tickes == 0) {
            System.out.println("售票结束。。。");
            loop = false;
            return;
        }
        System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票,剩余票数"+(--tickes));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

}
    @Override
 public void run() {
        while (loop) {
            sell();
        }

    }
}


在这里插入图片描述

分析同步原理

锁,在对象上

在这里插入图片描述

互斥锁

基本介绍

在这里插入图片描述

注意事项

在这里插入图片描述

简单案例

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: no
 * @Version: 1.0
 */

public class demo05 {
    public static void main(String[] args) {
        SellTickets3 sellTicket = new SellTickets3();
        Thread thread1 = new Thread(sellTicket);
        Thread thread2 = new Thread(sellTicket);
        Thread thread3 = new Thread(sellTicket);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class SellTickets3 implements Runnable{
    private  int tickes = 100;   //多个线程共享tickes
    private boolean loop  =true;
    Object object = new Object();

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


    //说明:
    // 1. public synchronized void sell()  就是一个同步方法
    // 2. 这时候,锁在this对象上
    // 3. 也可以在代码块上写synchronized,同步代码块,互斥锁还是在this对象上
    public /*synchronized8*/ void sell(){ 同步方法,在同一时刻,只能有一个线程来执行m方法
        synchronized (/*this*/ object){
            if (tickes <= 0) {
                System.out.println("售票结束。。。");
                loop = false;
                return;
            }
            System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票,剩余票数"+(--tickes));
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

}
    @Override
 public void run() {
        while (loop) {
            sell();
        }

    }
}


在这里插入图片描述

线程死锁

基本介绍

多个线程都占用了对方锁的资源,但不肯相让,导致了死锁。在编程时,要避免死锁的发生。

应用案例

妈妈:你先完成作业,才让你玩手机

小明:你让我玩手机,我才写作业

package 线程;

/**
 * @Author: 韩如意
 * @CreateTime: 2025-02-25
 * @Description: 模拟死锁
 * @Version: 1.0
 */

public class demo12 {
    public static void main(String[] args) {
        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        DeadLockDemo B = new DeadLockDemo(false);
        A.start();
        B.start();
        /*控制台卡在这里了:
        Thread-1进入3
        Thread-0进入1*/
    }
}
//线程
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为T,线程A就会先得到/持有 o1对象,然后尝试去获取噢对象锁
        //2. 如果线程A得不到o2对象锁,就会Blocked
        //3. 如果Flag为F,线程B就会得到/持有 o2对象锁,然后尝试去获取o1对象锁
        //4. 如果线程B 得不到o1 对象锁,就会Blocked
        //
        if(flag){
            synchronized (o1) {  //对象互斥锁,下面就是我们的同步代码
                System.out.println(Thread.currentThread().getName()+"进入1");
                synchronized (o2) {  //这里获取o1对象的监视权
                    System.out.println(Thread.currentThread().getName()+"进入2");
                }
            }
        }else {
            synchronized (o2) {
                System.out.println(Thread.currentThread().getName()+"进入3");
                synchronized (o1) {  //这里获取o2对象的监视权
                    System.out.println(Thread.currentThread().getName()+"进入4");
                }
            }
        }
    }
}

释放锁

以下操作会释放锁

在这里插入图片描述

下列操作不会释放锁

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值