java基础-10-多线程

  • 多线程
    • 概念
    • 创建线程与基本使用
    • 线程终止
    • 线程常用方法
    • 用户线程和守护线程
    • 线程生命周期,线程七大状态
    • 线程同步机制
    • 线程的死锁
    • 释放锁

多线程

概念

  • 进程:进程就是运行中的程序,比如打开qq,就是一个进程,操作系统会为他分配内存,进程是程序的一次执行过程,是一个动态过程
  • 线程:线程由进程创建,是进程的一个实体,一个进程可以有多个线程
  • 并发:一个cpu同时执行多个任务,来回切换
  • 并行:多个cpu各自执行一个任务,并行中也可能含有并发,即其中可能有一个cpu执行多个任务。

创建线程与基本使用

  • 创建一个线程类有两种方法,
  1. 第一种是继承Thread类,第二种是实现Runnable接口,Thread类实现了Runnable接口。
  2. 线程类中需要重写run方法,run方法中写自己的业务逻辑
  • Thread.sleep()用来休眠
  • Thread.currentThread()返回当前正在执行的线程的引用,getname()用于返回线程名
  • 在主函数中启动线程用start方法,不会阻塞,start方法里面再调用start0方法,start0是本地方法,由虚拟机调用,
  • run方法是一个普通方法,不会开线程,如果直接调用run方法就会阻塞,而不是开线程
  • jconsole可以用于实时看线程结束
public class Thread01 {  
    public static void main(String[] args) throws Exception{  
        Dog dog = new Dog();  
        dog.start();//启动线程  
  
        for (int i = 0; i < 50; i++) {  
            System.out.println(Thread.currentThread().getName()+"  "+i);  
            Thread.sleep(500);  
        }  
  
  
    }  
}  
class Dog extends Thread{  
    int times=0;  
    @Override  
    public void run() {  
        while(true) {  
	            System.out.println("汪汪汪" + (++times)+          Thread.currentThread().getName());  
  
            if (times==20){  
                break;  
            }  
  
            try {  
                Thread.sleep(500);//休眠,需要捕获异常
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
  
        }  
    }  
  • 实现Runnable接口来开发进程类,适用于该类继承了其他类,并且利于共享资源,即开多个线程都调用某个类的run方法,
  • 但是start方法在Thread类中,所以当启动进程时需要把这个进程赋给Thread对象。使用了代理模式
public class test02 {  
    public static void main(String[] args) {  
        Cat2 cat2 = new Cat2();  
  
        Thread thread = new Thread(cat2);  //赋给Thread对象
        thread.start();  
  
  
  
    }  
}  
class Animal{  
  
}  
class Cat2 extends Animal implements Runnable{  
    @Override  
    public void run() {  
        while (true) {  
            System.out.println("hi");  
            try {  
                Thread.sleep(200);  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
}

线程终止

run方法内有while循环来不停执行代码,通过改变while的判断条件来停止进程
具体就是while中传入参数,想要停止进程时,把参数改为false

public class test05 {  
    public static void main(String[] args) {  
        T t = new T();  
        t.start();  
  
        try {  
            Thread.sleep(5000);  
        } catch (InterruptedException e) {  
            throw new RuntimeException(e);  
        }  
  
  
        t.setLoop(false);//把进程停止  
        System.out.println("T运行停止");  
  
    }  
}  
class T extends Thread{  
    Boolean loop=true;  
    @Override  
    public void run() {  
  
        while (loop) {//控制进程停止  
            try {  
                Thread.sleep(100);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
            System.out.println("T在运行");  
        }  
    }  
  
    public void setLoop(Boolean loop) {  
        this.loop = loop;  
    }  
}

线程常用方法

  • start 启动线程
  • Thread.sleep ,static方法,休眠,
  • interrupt 中断线程的休眠
  • getName 得到线程的名字
  • setName 设置线程的名字
  • getPriority 得到线程的优先级
  • setPriority 设置线程的优先级
  • setDaemon方法:把一个线程设置成守护线程,注意:需在start前写
  • Thread.yield,static方法,线程的礼让,让出cpu让其他线程执行,但不一定会成功(当cpu充分时不会成功)
  • join,线程的插队,让其他线程先执行,并且一定当其他线程执行完后才会回来执行当前线程

案例1:

public class test06 {  
    public static void main(String[] args) throws Exception{  
  
        T1 t1 = new T1();  
        Thread thread = new Thread(t1);  
        thread.start();  
  
        for (int i = 0; i < 5; i++) {  
            Thread.sleep(1000);  
            System.out.println("主线程在执行");  
        }  
        thread.interrupt();//中断休眠  
  
  
    }  
}  
class T1 implements Runnable{  
    @Override  
    public void run() {  
        while (true) {  
            for (int i = 0; i <= 100; i++) {  
                System.out.println(Thread.currentThread().getName() + " 正在执行" + i);  
            }  
            try {  
                Thread.sleep(50 * 1000);  
            } catch (InterruptedException e) {  
                System.out.println(Thread.currentThread().getName() + " 的休眠被中断了");  
            }  
  
        }  
    }  
}

案例2:

public class test07 {  
    public static void main(String[] args) {  
  
        T2 t2 = new T2();  
        Thread thread = new Thread(t2);  
        thread.start();  
  
        for (int i = 0; i < 20; i++) {  
            System.out.println("hi,主线程"+i);  
            if(i==4){  
//                try {  
//                    join方法,直接让子线程插队  
//                    thread.join();  
  
                    //礼让,不一定会成功  
                    Thread.yield();  
//                } catch (InterruptedException e) {  
//                    throw new RuntimeException(e);  
//                }  
            }  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
}  
class T2 implements Runnable{  
    int count=0;  
    @Override  
    public void run() {  
  
        while (true){  
            count++;  
            System.out.println("hello,子线程"+count);  
  
            if (count==20){  
                break;  
            }  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
}

用户线程和守护线程

  • 用户线程:也叫工作线程,当线程的任务执行完后或以通知方式结束
  • 守护线程:一般是为工作线程服务的,当所有的工作线程结束后,守护线程自动结束
  • (守护线程在start后就会工作,在所有线程结束后,就会自动结束)
  • 常见的守护线程:垃圾回收机制
    setDaemon方法:把一个线程设置成守护线程,注意:需在start前写
public class test08 {  
    public static void main(String[] args) {  
  
        T3 t3 = new T3();  
        Thread thread = new Thread(t3);  
        thread.setDaemon(true);  
        thread.start();  
  
  
        for (int i = 0; i < 10; i++) {  
            System.out.println("主线程在工作"+i);  
//            if ()  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
  
        }  
  
    }  
}  
class T3 implements Runnable{  
  
    @Override  
    public void run() {  
  
        while (true){  
              
            System.out.println("hello,子线程");  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
}

线程生命周期,线程七大状态

Pasted image 20240229194429.png

线程同步机制

通过synchronized方法实现线程同步,对象互斥锁

  1. 放在方法声明中,表示整个方法为同步方法

public synchronized void m(){

}//这就是一个实现了线程同步的方法,同一时刻只能有一个线程在调用这个方法

举例可以用来改进卖票程序会超卖和重票问题

public class test04 {  
    public static void main(String[] args) {  
        SellTecket sellTecket = new SellTecket();  
        Thread thread = new Thread(sellTecket);  
        Thread thread2 = new Thread(sellTecket);  
        Thread thread3 = new Thread(sellTecket);  
        thread.start();  
        thread2.start();  
        thread3.start();  
  
    }  
}  
class  SellTecket implements Runnable{  
    private int TecketNum=100;  
    private  boolean loop=true;  //用来控制线程结束
    public synchronized void sell(){  //一个线程进入sell后,其他线程就不能进入
        if (TecketNum <= 0) {  
            System.out.println("票卖完了");  
            loop=false;  
            return;        }  
        try {  
            Thread.sleep(50);  
        } catch (InterruptedException e) {  
            throw new RuntimeException(e);  
        }  
        System.out.println(Thread.currentThread().getName() + "正在售票,余票为" + (--TecketNum));  
    }  
  
    @Override  
    public  void run() {  
  
        while (loop) {  
            sell();  
        }  
    }  
}
  1. 同步代码块

synchronized(){
//内容

}

public  void sell(){  //一个线程进入sell后,其他线程就不能进入  
    synchronized (this) {  
        if (TecketNum <= 0) {  
            System.out.println("票卖完了");  
            loop = false;  
            return;        }  
        try {  
            Thread.sleep(50);  
        } catch (InterruptedException e) {  
            throw new RuntimeException(e);  
        }  
        System.out.println(Thread.currentThread().getName() + "正在售票,余票为" + (--TecketNum));  
    }  
}

(非静态的)同步方法的锁可以是this,也可以是其他对象,但要求是同一对象
(静态的)同步方法的锁是类本身
静态举例:

public static void M(){  
    synchronized (SellTecket.class){  
        System.out.println("hello");  
    }  
}

线程的死锁

多个线程都占用了对方的锁资源,但不肯相让,导致了死锁

public class test09 {  
    public static void main(String[] args) {  
        T9 t9 = new T9(true);  
        T9 t92 = new T9(false);  
        Thread thread1 = new Thread(t9);  
        Thread thread2 = new Thread(t92);  
        thread1.start();  
        thread2.start();  
  
    }  
}  
class T9 implements Runnable{  
    public static Object obj1=new Object();  
    public static Object obj2=new Object();  
    boolean loop;  
  
    public T9(boolean loop) {  
        this.loop = loop;  
    }  
  
    @Override  
    public void run() {  
        if (loop){  
            synchronized (obj1){  
                System.out.println(" 占用了2");  
                synchronized (obj2){  
                    System.out.println("占用了1");  
                }  
            }  
        }else {  
            synchronized (obj2) {  
                System.out.println(" 占用了1");  
                synchronized (obj1) {  
                    System.out.println("占用了2");  
                }  
            }  
        }  
    }  
}

//但上述代码不一定会死锁,与线程的调度有关,如当thread1拿到obj1锁后,立刻又拿到了obj2锁,然后把这两个锁都释放了,这时thread2线程还没有开始,这种情况就不会死锁

释放锁

有四种情况会释放锁

  1. 当前线程的同步方法,同步代码块执行结束时
  2. 当前线程在同步方法,同步代码块遇到break,return退出了
  3. 在同步方法,同步代码块遇到Error或Exception
  4. 当前线程在同步方法,同步代码块执行了wait()方法,当前线程暂停,并释放锁
  5. (执行sleep()方法,yield()方法不会释放锁)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值