Day25-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\Threadcase-多线程讲到等待唤醒机制的一半

多线程

进程

进程是程序的基本执行实体

线程

线程是操作系统能够进行运算调度的最小单位,它被包含在进程中,是进程中实际运行的基本单位

应用软件中相互独立,可以独立运行的功能

多线程就是同时运行多个子程序,提高效率

并发

在同一时刻,有多个指令在单个CPU上交替运行

并行

在同一时刻,有多个指令在多个CPU上同时运行

image-20251028130038443

image-20251028131448799

package Basic.src.com.Threadcase.Threadcase1;

public class MyThread extends Thread{
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"Hello,World");
        }
    }
}
package Basic.src.com.Threadcase.Threadcase1;

public class ThreadDemo {
    /*
    * 多线程的第一种启动方式:
    * 1.定义一个类其继承thread类
    * 2.重写里面的run方法
    * 3.创建子类的对象,并启动线程
    *
    * */
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        //start()才表示开启线程
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        t2.start();

    }
}
package Basic.src.com.Threadcase.Threadcase2;

public class MyRun implements Runnable{
    private String name;
    @Override
    public void run() {
        //书写线程需要的代码
        for (int i = 0; i <100; i++) {
            Thread t = Thread.currentThread();//getName方法得在Thread类里面找
            System.out.println(t.getName()+"Hello World");
            System.out.println(Thread.currentThread().getName()+"Hello World!");
        }
    }
}
package Basic.src.com.Threadcase.Threadcase2;

public class ThreadDemo {
    /*
    * 多线程的第二种启动方式:
    * 1.自己定义一个类实现Runnable接口
    * 2.重写里面的run方法
    * 3.创建自己的类的对象
    * 4.创建一个Thread类对象并开启线程
    *
    *
    * */
    public static void main(String[] args) {
        //创建MyRun对象
        //表示多线程要执行的任务
        MyRun mr = new MyRun();

        //创建线程对象
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        //线程设置名字
        t1.setName("Thread1");
        t2.setName("Thread2");


        //开启线程
        t1.start();
        t2.start();
    }
}
package Basic.src.com.Threadcase.Threadcase3;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {//Integer是返回的结构的类型
    @Override
    public Integer call() throws Exception {
        //求1~100之间的和
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}
package Basic.src.com.Threadcase.Threadcase3;

import Basic.src.com.Threadcase.Threadcase1.MyThread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadDemo {
    /*
     * 多线程的第三种启动方式:
     * 特点:可以获取到多线程运行的结构
     * 1.自己定义一个MyCallable类实现Callable接口
     * 2.重写里面的call方法,有返回值
     * 3.创建自己的MyCallable类的对象
     * 4.创建一个FutureTask类对象作用管理多线程运行的结果
     *5.创建Thread类的对象,并启动(表示线程)
     *
     * */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3.创建自己的MyCallable类的对象,表示多线程要执行的任务
        MyCallable mc = new MyCallable();
        //4.创建一个FutureTask类对象作用管理多线程运行的结果
        FutureTask<Integer> ft = new FutureTask<>(mc);
        //5.创建Thread类的对象,并启动(表示线程)
        Thread t1 = new Thread(ft);//public Thread(Runnable target)
        //启动线程
        t1.start();

        //获取多线程
        Integer res = ft.get();
        System.out.println(res);
    }
}

抢占式调度(与非抢占式调度区别)

抢占式调度:随机

具有优先级

package Basic.src.com.Threadcase.ThreadPriority;

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            Thread t = Thread.currentThread();
            System.out.println(t.getName()+"---------"+i);
        }
    }
}
package Basic.src.com.Threadcase.ThreadPriority;

public class ThreadDemo {
    public static void main(String[] args) {
        //创建线程所要执行的参数对象
        MyRunnable mr = new MyRunnable();
        //创建线程对象
        Thread t1 = new Thread(mr,"飞机");
        Thread t2 = new Thread(mr,"坦克");

        System.out.println(t1.getPriority());//默认优先级是5
        System.out.println(t2.getPriority());
        System.out.println(Thread.currentThread().getPriority());//5
        //优先级越高抢到cpu的概率就越高
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
    }
}

守护线程

package Basic.src.com.Threadcase.DaemonThread;

public class MyThread1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i <= 10; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

package Basic.src.com.Threadcase.DaemonThread;

public class MyThread2 extends Thread {
    public void run() {
        for (int i = 0; i <= 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}
package Basic.src.com.Threadcase.DaemonThread;

import Basic.src.com.Threadcase.Threadcase1.MyThread;

public class ThreadDemo {
    public static void main(String[] args) {
        /*
        * 当其他非守护线程执行结束后,守护线程也会陆续结束
        * 当女神线程结束了,备胎也没有存在的必要
        * */
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();

        t1.setName("女神");
        t2.setName("备胎");

        //把第二个线程设置为守护线程(备胎线程)
        t2.setDaemon(true);

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

出让线程

package Basic.src.com.Threadcase.Threadyield;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
            //表示出让当前CPU的执行权
            Thread.yield();//提高均匀度(一定程度上)
        }
    }
}
package Basic.src.com.Threadcase.Threadyield;

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("飞机");
        t2.setName("坦克");
        t1.start();
        t2.start();
    }
}

插入线程

package Basic.src.com.Threadcase.ThreadJoin;

    public class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+"@"+i);

            }
        }
    }
package Basic.src.com.Threadcase.ThreadJoin;

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        /*
        *
        * */

        MyThread t = new MyThread();
        t.setName("土豆");
        t.start();
        //把t线程插入到当前线程之前:当前main线程
        t.join();

        //执行在main线程中
        for (int i = 0; i <= 10; i++) {
            System.out.println("main"+i);
        }

    }
}

代码的生命周期

image-20251028162130440

线程安全

同步代码块

package Basic.src.com.Threadcase.ThreadTicket;

public class MyThread extends Thread{
    static int ticket = 0;//static表示这个类所有的对象共享ticket,不加会卖票300张
    @Override
    public void run() {
        while (true) {
            //同步代码块
            synchronized (MyThread.class) {//锁对象一定要是唯一的
                if (ticket < 100) {
                    try {
                        Thread.sleep(100);//睡眠时没有CPU执行权,会被其他线程抢走
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    ticket++;
                    System.out.println(getName()+"正在卖票第"+ ticket+"张票!!");
                }else{
                    break;
                }
            }
        }
    }
}
package Basic.src.com.Threadcase.ThreadTicket;

public class ThreadDemo {
    public static void main(String[] args) {
        /*
        * 需求:某电影院正在上映国产大片,一共有100张票,而他有三个窗口卖,请设计一个程序模拟电影院卖票
        * */
        //创建线程对象
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();

        //起名字
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

}

同步方法

image-20251028170054687

package Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1;

public class MyRunnable implements Runnable {
    int ticket = 0;

    @Override
    public void run() {
        //1.循环
        //2.同步代码块(同步方法)
        //3.判断共享数据是否到了末尾,如果到了末尾
        //4.判断共享数据是否到了末尾,如果没有到末尾
        while (true) {
                if (method()) break;
        }
    }

    //ctrl+alt+M
    //this默认(非静态),此时是唯一的,因为MyRunnable只实现了一次
    private synchronized boolean method() {
        //达到末尾
        if (ticket == 100) {
            return true;
        }
        //没有达到末尾
        else  {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket++;
            System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");
        }
        return false;
    }
}
package Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1;

public class ThreadDemo {
    /*
     * 需求:某电影院正在上映国产大片,一共有100张票,而他有三个窗口卖,请设计一个程序模拟电影院卖票
     * 利用同步方法完成
     * 技巧:同步代码块
     * */
    public static void main(String[] args) {

        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);
        Thread t3 = new Thread(mr);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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


    }
}

StringBuilder和StringBuffer

StringBuilder非线程安全

StringBuffer线程安全

Lock锁

是接口不能直接实例化,可以采用它的实现类ReentrantLock来实例化

package Basic.src.com.Threadcase.ThreadSafe.Lock;

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

public class MyThread extends Thread {
    static int ticket = 0;
    static Lock lock = new ReentrantLock();//Lock是接口不能直接实例化
    //必须加上static关键字在lock前面,否则就是三个对象三把锁
    //如果锁对象不声明为 static,则它是实例成员变量—— 每个类的实例会拥有独立的锁对象。
    // 此时,不同实例的线程会持有不同的锁,无法实现跨实例的同步,导致同步失效。

    @Override
    public void run() {
        while (true) {
            //同步代码块,不能写在循环外面,否则会一直是一个窗口抢票
            //synchronized (Basic.src.com.Threadcase.ThreadSafe.Lock.MyThread.class) {//锁对象一定要是唯一的。MyThread.class表示当前类的字节码文件对象
            lock.lock();//上锁与synchronized重复
            try {
                if (ticket == 100) {
                    break;//break会跳过unlock,
                }
                //没有达到末尾
                else  {
                        Thread.sleep(100);
                    ticket++;
                    System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {//finally里面保证了锁一定被释放
                lock.unlock();//开锁
            }

            //}
        }
    }
}

package Basic.src.com.Threadcase.ThreadSafe.Lock;

import Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1.MyRunnable;

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



        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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


    }
}

死锁

是一个错误

指的是锁的嵌套

package Basic.src.com.Threadcase.ThreadSafe.DeadLock;

public class MyThread extends Thread{

    static Object objA = new Object();
    static Object objB = new Object();

    @Override
    public void run() {
        while(true){
            if("线程A".equals(Thread.currentThread().getName())){
                synchronized (objA){
                    System.out.println("线程A拿到了A锁,准备拿B锁");
                    synchronized (objB){
                        System.out.println("线程A拿到了B锁,顺利执行完一轮");
                    }
                }
            } else if ("线程B".equals(Thread.currentThread().getName())) {
                synchronized (objB){
                    System.out.println("线程B拿到了B锁,准备拿A锁");
                    synchronized (objA){
                        System.out.println("线程B拿到了A锁,顺利执行完一轮");
                    }
                }
            }

        }
    }
}
package Basic.src.com.Threadcase.ThreadSafe.DeadLock;

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("线程A");
        t2.setName("线程B");
        t1.start();
        t2.start();

    }
}

等待唤醒机制

生产者和消费者

image-20251028182301622

image-20251028182448488

未讲完

posted @ 2025-10-28 18:42  David大胃  阅读(7)  评论(0)    收藏  举报