多线程基础

1.进程和线程

进程:一个程序一次执行的过程
线程:一个进程执行会产生多个线程,Java中,主线程和子线程为并发执行

2.并发和并行

并行:多核cpu同时执行多个任务,真正意义上的同时
并发:一个cpu交替执行多个任务,宏观同时,微观交替执行

3.继承Thread类执行start方法

创建一个类继承Thread类,重写run方法,创建类对象,调用start方法启动线程

package com.hspedu.threaduse;

public class Thread01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.start();
    }
}

class Cat extends Thread{
    private int time = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("喵喵,我是小猫咪"+(++time));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(time == 8){
                break;
            }
        }

    }
}

4.线程执行的机制

主线程调用方法启动子线程时不会造成主线程的阻塞,主线程和子线程并发执行,当主线程消亡时子线程并不会随之消亡,而是等到该线程执行完毕后再消亡,两者在消亡上并没联系。

5.Runable创建线程

定义类实现Runnable接口,重写run方法,创建实现类对象,创建Thread对象,将实现类对象作为Thread类构造方法参数,Thread对象调用start方法祁启动线程。
使用Runnable接口可以更好利用共享资源,并且解决了java单继承的弊端

package com.hspedu.threaduse;

public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Thread thread = new Thread(dog);
        thread.start();
    }

}
class Dog implements 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;
            }
        }
    }
}

6.通知线程退出

在线程中定义一个状态值,并定义一个set方法,由其他线程调用set方法改变线程的状态值,通知线程退出

package com.hspedu.exit;

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

        Thread.sleep(1000);
        t1.setFlag(false);
    }
}

class T1 implements Runnable {
    private int count = 0;
    Boolean flag = true;


    public void setFlag(Boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        while (flag) {
            System.out.println("T运行中"+(count++));
        }
    }
}

7.线程第一组常用方法

常用方法
常用方法
注意事项
注意事项

package com.hspedu.method;

public class ThreadMehod {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        //给线程设置名称
        t.setName("老韩");
        //给线程设置优先级,最高为10,最低为1,默认为5
        t.setPriority(t.MIN_PRIORITY);
        t.start();

        //主线程打印5个hi,就中断子线程
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("hi"+i);
        }
        //得到子线程的优先级
        System.out.println(t.getName()+"的优先级是"+t.getPriority());
        //执行到这里时就会中断子线程的休眠,即唤醒子线程
        t.interrupt();
    }
}

class T extends Thread{
    @Override
    public void run(){
        while(true){
            for(int i = 0;i<100;i++){
                //Thread.currentThread().getName():获取当前线程名称
                System.out.println(Thread.currentThread().getName()+"吃包子~");
            }
            try {
                //使线程休眠20000毫秒
                System.out.println("休眠中~");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                //当线程执行到interrupt方法时就会catch一个异常
                System.out.println(Thread.currentThread().getName()+"被打断");
            }
        }
    }
}

8.线程第二组常用方法

在这里插入图片描述
礼让只是让线程进入就绪态,然后cpu重新对线程进行调度,所以不一定会成功。

package com.hspedu.method;

public class ThreadMethod01 {
    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("主线程让子线程先吃");
                //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 + "个包子");
        }
    }
}

9.守护线程

在这里插入图片描述

package com.hspedu.method;

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        DaemonThread  d = new DaemonThread();
        d.setDaemon(true);//将子线程设置为守护线程,当主线程结束后,守护线程就结束
        d.start();
        for(int i = 0;i<=20;i++){
            Thread.sleep(1000);
            System.out.println("王宝强在辛苦的工作");
        }
    }
}

class DaemonThread extends Thread{
    @Override
    public void run(){
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("马蓉和宋洁在快乐的聊天");
        }
    }
}

10.线程七大状态

在这里插入图片描述
NEW状态:当线程被创建之后,在启动之前线程处于New状态。

Runnable状态:当线程启动后进入Runnable状态,该状态分为Ready状态和Running状态,处于Ready状态的线程等待cpu调度进入Running状态,Running状态也可转换成Ready,详细见上图。

BLOCKED状态:线程等待锁的释放。

TIMED_WAITING状态:线程等待特定的时间。调用了sleep,或者带超时的Object.wait,带超时的join

WAITING状态:线程等待状态。可能因为调用Object.wait没有超时,Thread.join没有超时,LockSupport.park。 线程等待状态是正在等待另一个线程执行特定操作。

TERMINATED状态:线程的结束。

11.线程同步机制

简单理解就是在同一个时刻一个数据只能有一个线程对其进行操作在这里插入图片描述
同步机制解决售票问题

package com.hspedu.ticket;

public class SellTicket02 {
    public static void main(String[] args) {
        Selltocket3 selltocket3 = new Selltocket3();
        new Thread(selltocket3).start();
        new Thread(selltocket3).start();
        new Thread(selltocket3).start();
    }
}
class Selltocket3 implements Runnable{
    private int ticketNum = 100;
    Boolean loop = true;
    @Override
    public void run(){
        while(loop){
            sell();

        }
    }

    private synchronized void sell(){//同步方法,在同一时刻,只能有一个线程执行该方法
        if(ticketNum<=0){
            System.out.println("票卖完啦");
            loop = false;
            return;
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"售出一张票,还剩"+(--ticketNum)+"张票");
    }
}

12.互斥锁

分析同步原理
当三线程t1,t2,t3执行同一段同步代码块时,t1,t2,t3抢夺同步代码块对象的锁,这里假设t1抢到锁,即t1执行同步代码块,执行完后将所放回锁对象,然后t1,t2,t3再次对锁进行抢夺。(锁是锁在对象上不是在代码块上)
在这里插入图片描述
可以是同步代码块或同步方法的方式,多个线程必须抢夺同一把锁
在这里插入图片描述
在这里插入图片描述
静态方法锁为类本身,非静态方法默认锁为类的对象this
在这里插入图片描述
注意:用继承Thread类创建线程时,多个线程当中的this不是同一个对象,即当锁对象为this时,多个线程之间抢夺的不是同一把锁。

13.死锁

在这里插入图片描述
死锁例子:
线程a先得到了o1,必须的到o2才能释放o1;与此同时线程b先得到了o2,必须的到o1才能释放o2,两者僵持造成死锁。

package com.hspedu.syn;

public class DeadLock {
    public static void main(String[] args) {
        DeadLockDemo a = new DeadLockDemo(true);
        DeadLockDemo b = new DeadLockDemo(false);
        a.start();
        b.start();
    }
}

class DeadLockDemo extends Thread{
    static Object o1 = new Object();
    static Object o2 = new Object();
    Boolean flag;

    public DeadLockDemo(Boolean flag){
        this.flag = flag;
    }

    //如果flag为true,则线程A获得o1,然后尝试获得o2
    //如果线程A得不到o2,就会BLOCKED
    // 如果flag为false,则线程B获得o2,然后尝试获得o1
    //如果线程B得不到o1,就会BLOCKED
    @Override
    public void run(){
        if(flag){
            synchronized (o1){
                System.out.println("进入1");
                synchronized (o2){
                    System.out.println("进入2");
                }
            }
        }else{
            synchronized (o2){
                System.out.println("进入3");
                synchronized (o1){
                    System.out.println("进入4");
                }
            }
        }
    }
}

13.死锁

下面的操作会释放锁
在这里插入图片描述
下面的操作不会释放锁
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值