Java多线程(全知识点)

Java多线程

概述:本文为Java多线程的基础知识点的第一部分,主要包括,通过继承Thread来实现进程,线程调度,线程控制,run(),start(),join(),sleep(),setDaemon()方法的使用,获取线程名字currentThread(),线程同步,非静态锁,静态方法的锁,Lock锁,生产者与消费者问题,卖票问题。

简介

在这里插入图片描述
线程:是进程中的单个顺序控制流,是一条执行路径

  • 单线程:一个进程如果只有一条执行路径,则称为单线程程序
  • 多线程:一个进程如果有多条执行路径,则称为多线程程序

举例

  • 记事本属于单线程程序
  • 扫雷属于多线程程序

方式一

方式一继承Thread类

  • 定义一个类MyThread类
  • 在MyThread类中重写run()方法
  • 创建MyThread类的对象
  • 启动线程

两个问题

  • 为什么要重写run()方法
    因为run()是用来封装被线程执行的代码
  • run()方法和start()方法的区别
    run():封装线程执行代码,直接调用,相当于普通方法的调用
    start():启动线程;然后由JVM调用此线程的run()方法

run()

package com.one.container;
public class MyThreadDemo {
    public static class MyThread extends Thread{
        public MyThread(){}
        public MyThread(String name){  // 自定义一个有参的构成方法
            super(name);
        }
        @Override
        public void run() {
            for (int i = 0; i < 100; ++ i){
                System.out.println(getName()+":"+i);
            }
        }
    }
    public static void main(String[] args){
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();
        my1.setName("高铁");
        my2.setName("飞机");
        my1.run();  // run方法 相当于单线程的
        my2.run();

    }
}
}

运行结果
在这里插入图片描述

start()

讲解代码

package com.one.container;
import java.util.Scanner;
import java.util.Arrays;

public class Main {
	// 通过继承Thread类来创造属于自己的MyThread
    public static class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; ++ i){
                System.out.println(i);
            }
        }
    }
    public static void main(String[] args){
    	// 创建两个对象
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();
//        my1.run();  run方法 相当于单线程的
//        my2.run();
		// 然后调用start方法
        my1.start();
        my2.start();
    }
}

运行结果
在这里插入图片描述

设置和获取线程的名称

Thread.currentThread().getName():获取当当前的线程的名称

代码讲解

public class MyThreadDemo {
    public static class MyThread extends Thread{
        public MyThread(){}
        public MyThread(String name){  // 自定义一个有参的构成方法
            super(name);
        }
        @Override
        public void run() {
            for (int i = 0; i < 100; ++ i){
                System.out.println(getName()+":"+i);
            }
        }
    }
    public static void main(String[] args){

        // 自定义的有参构造方法 不需要直接调用setName设置线程名称
        MyThread my1 = new MyThread("高铁");
        MyThread my2 = new MyThread("飞机");
        my1.start();
        my2.start();

        // 返回对象前正在执行的线程对象的引用
        System.out.println(Thread.currentThread().getName());
    }
}

运行结果
在这里插入图片描述

线程调度

线程调度

线程有两种调度模型

  • 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占有的CPU的时间片
  • 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机一个,优先级高的线程获取的CPU时间片相对多一些

Java使用的抢占式的调度模型

假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令,所以说多线程程序在执行的是有随机性,因为谁抢到CPU的使用权是不一定的

Thread类中设置和获取线程优先级的方法

  • public final int getPriority(): 返回此线程的优先级
  • public final void setPriority(int new Priority): 更改此线程的优先级
    线程默认优先级是5;线程优先级的范围是:1-10
    线程优先级高仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要大家结果
public class MyThreadDemo {
    public static class ThreadPriority extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i ++){
                System.out.println(getName()+":"+i);
            }
        }
    }
    public static void main(String[] args){
        // 创建进程对象
        ThreadPriority tp1 = new ThreadPriority();
        ThreadPriority tp2 = new ThreadPriority();
        ThreadPriority tp3 = new ThreadPriority();

        // public final int getPriority();  // 返回线程的优先级
        System.out.println(tp1.getPriority());
        System.out.println(tp2.getPriority());
        System.out.println(tp3.getPriority());
        
        // 设置进程名字
        tp1.setName("高铁");
        tp2.setName("飞机");
        tp3.setName("汽车");

        // public final void setPriority(int newPriority); 更改此线程的优先级
        // tp1.setPriority(10000);
//        System.out.println(Thread.MAX_PRIORITY); // 最高优先级
//        System.out.println(Thread.MIN_PRIORITY); // 最小优先级
//        System.out.println(Thread.NORM_PRIORITY); // 正常优先级
        tp1.setPriority(Thread.NORM_PRIORITY);
        tp2.setPriority(Thread.MAX_PRIORITY);
        tp3.setPriority(Thread.MIN_PRIORITY);

        // 启动线程
        tp1.start();
        tp2.start();
        tp3.start();
    }
}

运行结果
在这里插入图片描述

线程控制

在这里插入图片描述

sleep

学习代码

public class MyThreadDemo {
    public static class ThreadSleep extends Thread{
        ThreadSleep(){}
        ThreadSleep(String name){
            super(name);
        }
        @Override
        public void run() {
            for (int i = 0; i < 100; i ++){
                System.out.println(getName()+":"+i);
                try{
                    Thread.sleep(1000);  // 休眠1s
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args){
        ThreadSleep ts1 = new ThreadSleep("曹操");
        ThreadSleep ts2 = new ThreadSleep("刘备");
        ThreadSleep ts3 = new ThreadSleep("孙权");

        ts1.start();
        ts2.start();
        ts3.start();
    }
}

运行结果
在这里插入图片描述

join

学习代码

public class MyThreadDemo {
    public static class ThreadJoin extends Thread{
        ThreadJoin(){}
        ThreadJoin(String name){
            super(name);
        }
        @Override
        public void run() {
            for (int i = 0; i < 10; i ++){
                System.out.println(getName()+":"+i);
            }
        }
    }
    public static void main(String[] args){
        ThreadJoin tj1 = new ThreadJoin("路飞");
        ThreadJoin tj2 = new ThreadJoin("索隆");
        ThreadJoin tj3 = new ThreadJoin("山治");

        tj1.start();
        try {
            tj1.join();  // 等路飞 这个线程结束了 下面两个线程才会
            // 执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        tj2.start();
        tj3.start();
    }
}

运行结果
在这里插入图片描述

setDaemon

在这里插入图片描述

学习代码

public class MyThreadDemo {
    public static class ThreadDaemon extends Thread{
        ThreadDaemon(){}
        ThreadDaemon(String name){
            super(name);
        }
        @Override
        public void run() {
            for (int i = 0; i < 10; i ++){
                System.out.println(getName()+":"+i);
            }
        }
    }
    public static void main(String[] args){
        ThreadDaemon td1 = new ThreadDaemon("善毅");
        ThreadDaemon td2 = new ThreadDaemon("山之助");

        // 设置主线程名字为炭之郎
        Thread.currentThread().setName("炭之郎");

        // 设置守护线程
        td1.setDaemon(true);  // 要写在start的前面
        td2.setDaemon(true);
        // 鬼灭之刃三人组 炭之郎死后 二位小弟也要一同共赴黄泉
        td1.start();
        td2.start();
        for (int i = 0; i < 10; ++ i){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

运行结果
在这里插入图片描述

在这里插入图片描述

方式二

在这里插入图片描述

学习代码

public class MyThreadDemo {

    // 通过继承Runnable接口来实现多线程
    public static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 10; ++ i){
                // 获取当前进程的名字
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    public static void main(String[] args){
        MyRunnable my = new MyRunnable();
        Thread t1 = new Thread(my, "高铁");
        Thread t2 = new Thread(my, "飞机");

        t1.start();
        t2.start();
    }
}

运行结果
在这里插入图片描述

线程同步

案例卖票

在这里插入图片描述

学习代码

public class MyThreadDemo {

    public static class SellTicket implements Runnable{
        // 默认有100张票
        private int ticket = 100;
        @Override
        public void run() {
            while (true){
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                    ticket --;
                }
            }
        }
    }
    public static void main(String[] args){
        SellTicket st = new SellTicket();

        // 定义对象
        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");

        t1.start();
        t2.start();
        t3.start();
    }

}

运行结果
在这里插入图片描述

改进之后的思考

在这里插入图片描述
学习代码

public class MyThreadDemo {

    public static class SellTicket implements Runnable{
        private int ticket = 100;
        @Override
        public void run() {
            while (true){
                if (ticket > 0){
                    try {  // 卖票的时候 添加休眠
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                    ticket --;
                }
            }
        }
    }
    public static void main(String[] args){
        SellTicket st = new SellTicket();

        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果
在这里插入图片描述

出现问题
在这里插入图片描述
在这里插入图片描述

原因分析

  1. 出现相同的票
    在这里插入图片描述

  2. 出现负数的票
    在这里插入图片描述

安全问题的解决方案

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

学习代码

public class MyThreadDemo {

        public static class SellTicket implements Runnable{
            private int ticket = 100;
            private Object obj = new Object();  // 在外面定义这个Object对象
            @Override
            public void run() {
                while (true){
                    synchronized (obj){  // 不要在这里面定义这个对象 不然3个进程会产生3把锁 还是不能解决问题
                        if (ticket > 0){
                            try {  // 卖票的时候 添加休眠
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                            ticket --;
                        }
                    }
                }
            }
        }
        public static void main(String[] args){
            SellTicket st = new SellTicket();

            Thread t1 = new Thread(st,"窗口1");
            Thread t2 = new Thread(st,"窗口2");
            Thread t3 = new Thread(st,"窗口3");

            t1.start();
            t2.start();
            t3.start();
        }

    }

运行结果
在这里插入图片描述

同步方法

在这里插入图片描述

非静态的锁

学习代码

 public class MyThreadDemo {
        public static class SellTicket implements Runnable{
            private int ticket = 100;
            private int x = 0;
            @Override
            public void run() {
                try {  // 卖票的时候 添加休眠
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                while (true){
                    if (x % 2  == 0){
                        synchronized (this){  // 非静态用的this这个锁
                            if (ticket > 0){
                                try {
                                    Thread.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                                ticket --;
                            }
                        }
                    } else {
                        sellTicket();
                    }
                }
            }
            private synchronized void sellTicket(){
                if (ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                    ticket --;
                }
            }
        }
        public static void main(String[] args){
            SellTicket st = new SellTicket();

            Thread t1 = new Thread(st,"窗口1");
            Thread t2 = new Thread(st,"窗口2");
            Thread t3 = new Thread(st,"窗口3");

            t1.start();
            t2.start();
            t3.start();
        }
    }

运行结果
在这里插入图片描述

静态方法的锁

学习代码

public class SellTicket implements Runnable{
    private static int ticket = 100;
    private int x = 0;
    @Override
    public void run() {
        try {  // 卖票的时候 添加休眠
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true){
            if (x % 2  == 0){
                synchronized (SellTicket.class){  // 静态的用这个锁
                    if (ticket > 0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                        ticket --;
                    }
                }
            } else {
                sellTicket();
            }
        }
    }
    private static synchronized void sellTicket(){
        if (ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
            ticket --;
        }
    }
线程安全的类

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

案例:生产者与消费者

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
学习代码

package Safe;

    public class MyThreadDemo {
        // 生产者类
        public static class Producer implements Runnable{
            private Box b;
            public Producer(Box b) {
                this.b = b;
            }

            @Override
            public void run() {
                for (int i = 1; i <= 5; ++ i){ // 放置牛奶
                    b.put(i);
                }
            }
        }

        // 消费者类
        public static class Customer implements Runnable{
            private Box b;
            public Customer(Box b) {
                this.b = b;
            }

            @Override
            public void run() {  // 获取牛奶
                while(true){
                    b.get();
                }
            }
        }
        // 奶箱类
        public static class Box{
            // 定义一个成员变量 表示第x瓶牛奶
            private int milk;

            // 定义一个成员变量,表示奶箱的状态
            private boolean state = false;

            // 提供存储牛奶和获取牛奶的操作
            // 存储牛奶
            public synchronized void put(int milk){
                // 如果有牛奶,等待消费
                if (state){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 如果没有牛奶,就生产牛奶
                this.milk = milk;
                System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");

                // 生产完毕之后,修改奶箱状态
                state = true;

                // 唤醒其他等待线程
                notifyAll();
            }

            // 获取牛奶
            public synchronized void get(){
                // 如果没有牛奶,等待生产
                if(!state){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 如果有牛奶,就消费牛奶
                System.out.println("用户拿到第"+this.milk+"瓶奶");

                // 消费完毕之后,修改奶箱状态
                state = false;

                // 唤醒其他等待线程
                notifyAll();
            }
        }
        public static void main(String[] args){
            // 创建奶箱对象,这是共享数据区域
            Box b = new Box();

            // 创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类种要调用存储牛奶的操作
            Producer p = new Producer(b);

            // 创建消费者对象,把牛奶对象作为构造方法参数传递,因为在这个类种要调用获取牛奶的操作
            Customer c = new Customer(b);

            // 创建两个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
            Thread t1 = new Thread(p);
            Thread t2 = new Thread(c);

            // 启动线程
            t1.start();
            t2.start();
        }

    }
    

运行结果
在这里插入图片描述

Lock锁

在这里插入图片描述

学习代码

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static class SellTicket implements Runnable{
        private int ticket = 100;
        private Lock lock = new ReentrantLock();
        @Override
        public void run() {
            while(true){
                try {
                    lock.lock();
                    if (ticket > 0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
                        ticket--;
                    }
                } finally {  // 为了使得这个锁怎么都可以释放 所以要用到finally关键字
                    lock.unlock();     
                }
            }
        }
    }
    public static void main(String[] args){
        SellTicket st = new SellTicket();
        Thread t1 = new Thread(st, "窗口一");
        Thread t2 = new Thread(st, "窗口二");
        Thread t3 = new Thread(st, "窗口三");
        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客李华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值