javaseday31多线程

news2024/9/26 14:44:40

什么是多线程

线程与进程

小结

并发和并行

并发

并行

小结 

多线程的实现方式

方法一

public class Demo1 {
    public static void main(String[] args) {
        //使用多线程的第一种方法
        /**
         * 1、创建一个类继承Thread类
         * 2、并重写run方法
         * 3、创建子类对象,并启动线程
         */
        MyThead m1= new MyThead();
        MyThead m2= new MyThead();

        //启动多线程不能使用对象直接调用run方法,需要调用start方法启动多线程
        //给两个线程设置名字用以区分
        m1.setName("线程1");
        m2.setName("线程2");

        m1.start();
        m2.start();
        /**
         * 线程2helloworld
         * 线程1helloworld
         * 线程2helloworld
         * 线程1helloworld
         * 线程2helloworld
         * 线程1helloworld
         * 线程1helloworld
         */
    }
}
public class MyThead extends Thread {
    @Override
    public void run() {
        //重写run方法,getName()为创建对象时赋值给该对象的名字,用于表示执行的是哪个线程,getName()为父类中的方法
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"helloworld");
        }
    }
}

方法二

public class Demo2 {
    public static void main(String[] args) {
        /**
         * 多线程的第二种方式
         * 1、创建类实现Runnable接口
         * 2、实现接口中的run方法
         * 3、创建子类对象
         * 4、将子类对象交给Thread线程对象进行操作
         */
        //由于是将对象交给线程对象所以只需要一个子类对象
        MyThread m1 = new MyThread();

        //将这两个对象交给线程
        Thread t1 = new Thread(m1);
        Thread t2 = new Thread(m1);

        //给两个线程对象赋值
        t1.setName("线程一");
        t2.setName("线程二");
        //开启线程
        t1.start();
        t2.start();

    }

}
public class MyThread implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //调用线程方法获取当前执行的线程的对象
            Thread thread = Thread.currentThread();
            //获取线程对象的名字
            System.out.println(thread.getName()+"halloWorld");
        }
    }
}

方法三:

public class Demo3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 多线程实现的第三种方式
         *      特点:可以获取多线程运行的结果
         *  1、创建一个类MyCallable实现Callable接口
         *  2、重写call方法(有返回值,表示多线程的运行结果)
         *  3、创建MyCallable对象(表示多线程执行的任务)
         *  4、创建FutureTask的对象(用于管理多线程运行的结果)
         *  5、创建Thread类的对象并启动(表示线程)
         *
         */
        //创建MyCallable对象(表示多线程执行的任务)
        MyCallable myCallable = new MyCallable();
        //创建FutureTask的对象(用于管理多线程运行的结果)
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        //创建Thread类的对象并启动(表示线程)
        Thread t = new Thread(futureTask);
        //启动线程
        t.start();
        //获取线程运行的结果
        Integer i = futureTask.get();
        System.out.println(i);


    }
}
public class MyCallable implements Callable<Integer> {
    /*
    Callable<Integer>的泛型表示返回值的类型
     */
    @Override
    public Integer call() throws Exception {
        //求1-100之间的额值
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum =sum +i;
        }
        return sum;
    }
}

三种实现方法的对比

常见的成员方法

public class Demo1 {
    public static void main(String[] args) {
               /*
            String getName()                    返回此线程的名称
            void setName(String name)           设置线程的名字(构造方法也可以设置名字)
            细节:
                1、如果我们没有给线程设置名字,线程也是有默认的名字的
                        格式:Thread-X(X序号,从0开始的)
                2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置

            static Thread currentThread()       获取当前线程的对象
            细节:
                当JVM虚拟机启动之后,会自动的启动多条线程
                其中有一条线程就叫做main线程
                他的作用就是去调用main方法,并执行里面的代码
                在以前,我们写的所有的代码,其实都是运行在main线程当中

            static void sleep(long time)        让线程休眠指定的时间,单位为毫秒
            细节:
                1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
                2、方法的参数:就表示睡眠的时间,单位毫秒
                    1 秒= 1000毫秒
                3、当时间到了之后,线程会自动的醒来,继续执行下面的其他代码
       */
        //1.创建线程的对象
        MyThead t1 = new MyThead("飞机");
        MyThead t2 = new MyThead("坦克");



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


        //哪条线程执行到这个方法,此时获取的就是哪条线程的对象
       /* Thread t = Thread.currentThread();
        String name = t.getName();
        System.out.println(name);//main*/

        /*System.out.println("11111111111");
        //线程停止5秒钟
        Thread.sleep(5000);
        System.out.println("22222222222");*/
    }
}
public class MyThead extends Thread {
    //重写父类的部分构造方法
    public MyThead() {
    }
//重写父类中给线程赋值名字的构造方法
    public MyThead(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                //线程的休眠,每次执行都会使线程休眠1秒钟
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //getName()表示线程的名字,如果没有赋值则使用默认的线程名,Thread+线程序号,从0开始
            System.out.println(getName() + "@" + i);
        }
    }
}

第二组成员方法

public class Demo2 {
    public static void main(String[] args) {
        //线程的优先级

        //创建线程
        MyThead m1 = new MyThead();


        Thread t1 = new Thread(m1,"坦克");
        Thread t2 = new Thread(m1,"飞机");

        //设置两个线程的优先级,最高位10最低位1,优先级为10不一定必定发生,优先级为1不一定不发生,这只是概率不同
        t1.setPriority(10);
        t2.setPriority(1);

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

        //获取main方法的优先级,5
//        System.out.println(Thread.currentThread().getPriority());
        
    }
}
public class MyThead extends Thread {


        @Override
        public void run() {
            for (int i = 1; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName() + "---" + i);
            }
        }

}

守护线程

public class Demo3 {
    public static void main(String[] args) {
        //备胎线程
        /**
         * 当其他线程结束时,备胎线程也会陆续结束(不一定是立即结束,但即使还没有运行完备胎线程,当其他进程结束时备胎线程也会结束)
         *
         */
        Threadgril tg = new Threadgril();
        Threadman tm = new Threadman();

        tg.setName("女神");
        tm.setName("备胎");

        //将tm线程设置为备胎线程
        tm.setDaemon(true);

        //启动两个线程
        tg.start();
        tm.start();
        /**
         * 女神女神进程9
         * 备胎备胎进程16
         * 备胎备胎进程17
         * 备胎备胎进程18
         * 备胎备胎进程19
         * 备胎备胎进程20
         * 女神线程结束时,备胎线程也陆续结束,且备胎线程没有完成
         */
    }
}
public class Threadgril extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"女神线程"+i);
        }
    }
}
public class Threadman extends Thread{
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"备胎线程"+i);
        }
    }
}

礼让线程(出让线程)

public class Demo4 {
    public static void main(String[] args) {
        /**
         * 礼让线程
         *礼让线程可以让线程的执行更加平均但是无法保证绝对的平均
         */
        //1.创建线程的对象
        threadmy t1 = new threadmy();
        threadmy t2 = new threadmy();
        //给线程赋名字
        t1.setName("飞机");
        t2.setName("坦克");
        
        //2.开启线程
        t1.start();
        t2.start();
    }
}
public class threadmy extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"="+i);
            //表示让出当前CPU的执行权
            Thread.yield();
        }
    }
}

插入线程

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
       /*
            public final void join()  插入线程/插队线程
       */



        MyThread t = new MyThread();
        t.setName("土豆");
        t.start();

        //表示把t这个线程,插入到当前线程之前。
        //当前线程为main线程,即插入到main线程之前,t线程结束后main线程才会执行
        //t:土豆
        //当前线程: main线程
        t.join();

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


    }
}
public class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(getName() + "@" + i);

        }
    }
}

线程的生命周期

线程安全

练习

public class Demo5 {
    public static void main(String[] args) {
        /**
         * 售票窗口有三个,可以看做三个线程
         * 当前代码有问题,一张票会被收买多次,且有超出100的情况
         * 窗口2窗口卖出的第100票
         * 窗口3窗口卖出的第101票
         * 窗口1窗口卖出的第102票
         * 窗口2窗口卖出的第2票
         * 窗口3窗口卖出的第2票
         * 窗口1窗口卖出的第2票
         */
        Mythread m1 = new Mythread();
        Mythread m2 = new Mythread();
        Mythread m3 = new Mythread();

        m1.setName("窗口1");
        m2.setName("窗口2");
        m3.setName("窗口3");

        m1.start();
        m2.start();
        m3.start();
    }
}
public class Mythread extends Thread{
    /**
     * 售票的窗口为线程
     */
    //设置静态变量记录售出的票数
    static int tacket = 0;

    @Override
    public void run() {
        while (true) {
            //当有线程执行时
            if (tacket<100){
                //每次停止0.1秒
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                tacket++;
                System.out.println(getName()+"窗口卖出的第"+tacket+"票");

            }else {
                break;
            }
        }
    }
}

同步代码块

同步代码块修改过后的买票窗口
public class Mythread extends Thread{
    /**
     * 售票的窗口为线程
     */
    //设置静态变量记录售出的票数
    static int tacket = 0;
    //锁对象可以是任意对象,但是一定要是唯一的,使用static静态变量修饰符
    static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            //同步代码块
            synchronized (obj){
                //当有线程执行时
                if (tacket<100){
                    //每次停止0.1秒
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    tacket++;
                    System.out.println(getName()+"窗口卖出的第"+tacket+"票");

                }else {
                    break;
                }
            }
        }
    }
}

小细节

  1. synchronized一定要在循环里面,如果在外面就会导致所用的循环都有一个线程执行
  2. 锁对象一定要唯一。不为一就相当于没有锁。可以使用该类的类对象即class对象,应为这个只能有一个如
    Mythread.class
public class Mythread extends Thread{
    /**
     * 售票的窗口为线程
     */
    //设置静态变量记录售出的票数
    static int tacket = 0;
    //锁对象可以是任意对象,但是一定要是唯一的,使用static静态变量修饰符
    static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            //同步代码块
            synchronized (Mythread.class){
                //当有线程执行时
                if (tacket<100){
                    //每次停止0.1秒
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    tacket++;
                    System.out.println(getName()+"窗口卖出的第"+tacket+"票");

                }else {
                    break;
                }
            }
        }
    }
}

同步方法

public class Demo5 {
    public static void main(String[] args) {
        methodthread mt = new methodthread();

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

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        
        t1.start();
        t2.start();
        t3.start();
    }
}
public class methodthread implements Runnable{
    int tacket = 0;

    @Override
    public void run() {
        while (true){
            if (method()) break;
        }
    }

    private synchronized boolean method() {

            if (tacket == 100){
                return true;
            }else {
                //使用同步代码块写在转换为同步方法
                tacket++;
                System.out.println(Thread.currentThread().getName()+"售卖了第"+tacket+"张票");
            }

        return false;
    }

}

Lock锁

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

        //1.创建线程的对象
        threadmy t1 = new threadmy();
        threadmy t2 = new threadmy();
        threadmy t3 = new threadmy();
        //给线程赋名字
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        //2.开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
public class threadmy extends Thread {
    /**
     * 售票的窗口为线程
     */
    //设置静态变量记录售出的票数
    static int tacket = 0;
    //lock锁
    //由于Lock是接口所以要使用他的实现类
    //static保证其只有一个
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true) {
            //加锁
            lock.lock();
            try {
                //当有线程执行时
                if (tacket < 100) {
                    //每次停止0.1秒
                    Thread.sleep(100);
                    tacket++;
                    System.out.println(getName() + "窗口卖出的第" + tacket + "票");

                } else {
                    break;
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                //将其放入finally中保证其无论如何都可被执行
                lock.unlock();
            }
        }
    }
}

死锁(是一个错误)

public class MyThread extends Thread {

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

    @Override
    public void run() {
        //1.循环
        while (true) {
            if ("线程A".equals(getName())) {
                synchronized (objA) {
                    System.out.println("线程A拿到了A锁,准备拿B锁");//A
                    synchronized (objB) {
                        System.out.println("线程A拿到了B锁,顺利执行完一轮");
                    }
                }
            } else if ("线程B".equals(getName())) {
                if ("线程B".equals(getName())) {
                    synchronized (objB) {
                        System.out.println("线程B拿到了B锁,准备拿A锁");//B
                        synchronized (objA) {
                            System.out.println("线程B拿到了A锁,顺利执行完一轮");
                        }
                    }
                }
            }
        }
    }
}
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();

    }
}

等待唤醒机制(生产者和消费者)

常见方法

public class Test {
    public static void main(String[] args) {
        fooder f = new fooder();
        cook c = new cook();

        f.setName("吃货");
        c.setName("厨师");

        f.start();
        c.start();
    }
}
package MyThead.foodwork;

public class fooder extends Thread {
    //消费者

    /**
     * 1、循还
     * 2、同步代码块
     * 3、判断共享数据是否到末尾
     * 4、判断共享数据是否到末尾(没有,执行核心逻辑)
     */
    @Override
    public void run() {
        while (true) {
            synchronized (desk.lock) {
                if (desk.count == 0) {
                    //应该停止
                    break;

                } else {
                    /**
                     * 1、判断桌上是否有食物
                     * 2、有则吃
                     * 3、没有则等待
                     * 4、吃完后唤醒厨师
                     * 5、吃的总数-1
                     * 6、修改桌子的数据
                     */
                    if (desk.foodFlag == 0) {
                        //使用锁对象调用是为了唤醒的时后进行精确唤醒
                        try {
                            desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        //有实物
                        //吃的总数-1
                        desk.count = desk.count - 1;
                        //开始吃
                        System.out.println(getName() + "开始吃了,还能在吃" + desk.count + "碗");
                        //修改桌子的数据
                        desk.foodFlag = 0;
                        //吃完后唤醒厨师
                        desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}
package MyThead.foodwork;

public class cook extends Thread {
    //生产者

    @Override
    public void run() {
        /**
         * 1、循还
         * 2、同步代码块
         * 3、判断共享数据是否到末尾
         * 4、判断共享数据是否到末尾(没有,执行核心逻辑)
         */
        while (true) {
            synchronized (desk.lock) {
                if (desk.count == 0) {
                    //应该停止
                    break;
                } else {
                    /**
                     * 1、判断桌上是否有食物
                     * 2、有则吃等待
                     * 3、没有则做
                     * 4、吃做后唤醒顾客
                     * 5、修改桌子的数据
                     */
                    if (desk.foodFlag == 1) {
                        //使用锁对象调用是为了唤醒的时后进行精确唤醒
                        try {
                            desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        //无实物
                        //开始做
                        System.out.println(getName() + "开始做");
                        //修改桌子的数据
                        desk.foodFlag = 1;
                        //吃完后唤醒顾客
                        desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}
package MyThead.foodwork;

public class desk {
    //桌子
    //有没有食物
    //有食物则吃货执行
    public static int foodFlag = 0;
    //加锁
    public static Object lock = new Object();

    //总的执行的个数
    public static int count = 10;


}

阻塞队列实现等待唤醒机制

public class Tes {
    public static void main(String[] args) {
        //阻塞队列,ArrayBlockingQueue<>(1)表示队列只有一个位置
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

        Cook c = new Cook(queue);
        Fooder f = new Fooder(queue);

        c.start();
        f.start();
    }
}
public class Cook extends Thread{
    //使用构造方法给阻塞队列赋初值保证两个线程使用同一个阻塞队列
    ArrayBlockingQueue<String> queue;

    public Cook(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true){
            try {
                queue.put("面条");
                System.out.println("厨师做了一碗面条");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Fooder extends Thread{
    //使用构造方法给阻塞队列赋初值保证两个线程使用同一个阻塞队列
    ArrayBlockingQueue<String> queue;

    public Fooder(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            String take = null;
            try {
                take = queue.take();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("食客吃了一碗"+take);
        }
    }
}

线程的状态

综合练习

练习一

public class threadmy extends Thread{
    //票数共1000张
    static int tacket = 1000;
    //加一个锁对象
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                lock.lock();
                //判断有没有票
                if (tacket == 0){
                    //没有票
                    break;
                }else {
                    Thread.sleep(3000);
                    //有票
                    tacket --;
                    System.out.println("这是"+getName()+"售卖的票,当前是第"+(1000-tacket)+"张票");
                    System.out.println("还剩余"+tacket+"张票");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                //保证无论如何都会打开锁
                lock.unlock();
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        threadmy t1 = new threadmy();
        threadmy t2 = new threadmy();

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

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

练习二

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

        t1.setName("人1");
        t2.setName("人2");

        t1.start();
        t2.start();
    }
}
public class threadmy extends Thread{
    //礼品共100份
    static int tacket = 100;
    //加一个锁对象
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                lock.lock();
                //判断礼品数量是否小于10
                if (tacket <= 10){
                    //礼品数量小于10
                    break;
                }else {
                    //间隔30毫秒
                    Thread.sleep(30);
                    //有礼物
                    tacket --;
                    System.out.println("这是"+getName()+"送的礼物,还剩余"+tacket+"个礼物");
                    System.out.println();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                //保证无论如何都会打开锁
                lock.unlock();
            }
        }
    }
}

练习三

public class threadTest3 extends Thread{
    static int num = 0;
    //锁
    Lock lock = new ReentrantLock();

    public void run() {
        while (true) {
            synchronized (threadTest3.class) { // 使用类级别锁
                if (num > 100) {
                    break;
                }

                // 判断是奇数
                if (num % 2 != 0) {
                    System.out.println(getName() + "这个数是奇数:" + num);
                }
                num++; // 增加 num
            }
        }
    }
        //会出现两个1
//    public void run() {
//        while (true){
//            lock.lock();
//            try {
//                //判断当前的数量
//                if (num>100){
//                    break;
//                }else {
//                    //判断是奇数还是偶数
//                    if (num%2==0){
//                        //偶数不进行处理
//                    }else {
//                        System.out.println(getName()+"这个数是奇数:"+num);
//                    }
//                }
//                num++;
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            } finally {
//                lock.unlock();
//            }
//        }
//    }
}
public class Test3 {
    public static void main(String[] args) {
        threadTest3 t1 = new threadTest3();
        threadTest3 t2 = new threadTest3();

        t1.setName("线程一");
        t2.setName("线程二");

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

练习四

public class threadTest4 extends Thread{
    //抢红包
    //总共的100元
    static int m = 100;

    //剩余红包数量
    static int num = 3;
    //抢红包的人数
    static int j = 5;

    //锁
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true){
            //将进入的进程都进行休眠以保证在这个周期中每个线程都可以运行一次
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            lock.lock();
            try {
                if (j==0){
                    break;
                }else {
                    j--;
                }
                //判断还有没有红包
                if (num == 0){
                    System.out.println(getName()+"没有抢到红包");
                } else if (num==1) {
                    //最后一个红包,全部给这个人
                    System.out.println(getName()+"抢到了"+m+"元");
                    //修改数据
                    m = 0;
                    num = 0;
                }else {
                    //其他情况
                    Random r = new Random();
                    //随机抢的钱数
                    int i = r.nextInt(m);
                    System.out.println(getName()+"抢到了"+i+"元");
                    //修改数据
                    m = m - i;
                    num--;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
}
public class Test4 {
    public static void main(String[] args) {
        threadTest4 t1 = new threadTest4();
        threadTest4 t2 = new threadTest4();
        threadTest4 t3 = new threadTest4();
        threadTest4 t4 = new threadTest4();
        threadTest4 t5 = new threadTest4();

        t1.setName("人一");
        t2.setName("人二");
        t3.setName("人三");
        t4.setName("人四");
        t5.setName("人五");

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

讲一 

public class Test4_2 {
    public static void main(String[] args) {
        thread2 t1 = new thread2();
        thread2 t2 = new thread2();
        thread2 t3 = new thread2();
        thread2 t4 = new thread2();
        thread2 t5 = new thread2();

        t1.setName("人一");
        t2.setName("人二");
        t3.setName("人三");
        t4.setName("人四");
        t5.setName("人五");

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

public class thread2 extends Thread{
    //红包的个数
    static int num = 3;
    //红包的总金额
    static double mon = 100;
    //红包的最小金额
    static final double MIN = 0.01;

    @Override
    public void run() {
        Random r = new Random();
        //每个线程执行一次不需要循化
            synchronized (thread2.class){
                //判断是否还有红包
                if (num==0){
                    System.out.println(getName()+"没领到红包");
                }else {
                    double price;
                   //判断是否是最后一个红包
                    if (num==1){
                        //将剩余的钱都放入这个红包
                        price = mon;
                    }else {
                        //随机红包的金额
                        //红包的限制
                        double n = mon - (num-1)*MIN;
                        double v = r.nextDouble(n);
                        price = v;
                        //如果小于最小值则强转变为最小值
                        if(price < MIN){
                            price = MIN;
                        }
                    }
                    mon = mon - price;
                    num--;
                    System.out.println(getName()+"抢到了红包 "+price+"元");
                }
            }

    }
}

讲二(保留2位小数) 

/**
 * 由于小数随机导致数据出现小数点后多位,使用BigDecimal来避免这种情况
 */
public class thread3 extends Thread{
    //红包的个数
    static int num = 3;
    //红包的总金额
    static BigDecimal m = BigDecimal.valueOf(100);
    //红包的最小金额
    static final BigDecimal MIN = BigDecimal.valueOf(0.01);

    @Override
    public void run() {
        Random r = new Random();
        //每个线程执行一次不需要循化
            synchronized (thread3.class){
                //判断是否还有红包
                if (num==0){
                    System.out.println(getName()+"没领到红包");
                }else {
                    BigDecimal price;
                   //判断是否是最后一个红包
                    if (num==1){
                        //将剩余的钱都放入这个红包
                        price = m;
                    }else {
                        //随机红包的金额
                        //红包的限制
                        BigDecimal minn = MIN.multiply(BigDecimal.valueOf(num-1));
                        BigDecimal n = m.subtract(minn);
                        BigDecimal v = BigDecimal.valueOf(r.nextDouble(n.doubleValue()));
                        price = v;
                        //如果小于最小值则强转变为最小值
                        price = price.max(MIN);
//                        if(price < MIN){
//                            price = MIN;
//                        }
                    }
                    m = m.subtract(price);
                    num--;
                    System.out.println(getName()+"抢到了红包 "+formatToNumber(price)+"元");
                }
            }

    }

    /**
     * @desc 1.0~1之间的BigDecimal小数,格式化后失去前面的0,则前面直接加上0。
     * 2.传入的参数等于0,则直接返回字符串"0.00"
     * 3.大于1的小数,直接格式化返回字符串
     * @param 
     * @return
     */
    public static String formatToNumber(BigDecimal obj) {
        DecimalFormat df = new DecimalFormat("#.00");
        if(obj.compareTo(BigDecimal.ZERO)==0) {
            return "0.00";
        }else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){
            return "0"+df.format(obj).toString();
        }else {
            return df.format(obj).toString();
        }
    }
}
public class Test4_3 {
    public static void main(String[] args) {
        thread3 t1 = new thread3();
        thread3 t2 = new thread3();
        thread3 t3 = new thread3();
        thread3 t4 = new thread3();
        thread3 t5 = new thread3();

        t1.setName("人一");
        t2.setName("人二");
        t3.setName("人三");
        t4.setName("人四");
        t5.setName("人五");

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

练习五

public class threadTest5 extends Thread{
    //创建一个静态的奖池
     static   ArrayList<Integer> list = new ArrayList<>();
    //给静态奖池赋值
    static {
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
    }
    //锁
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        Random r = new Random();
        while (true){
//            //使抽奖更加均衡
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //上锁
            lock.lock();
            try {
                //判断奖池中是否还有数据
                if (list.size()==0){
                    break;
                }else {
                    //定义随机数抽取数据
                    int i = r.nextInt(list.size());
                    //将数据打印
                    System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
                    //在list中删除该数据
                    list.remove(i);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
}

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

        t1.setName("抽奖箱一");
        t2.setName("抽奖箱二");

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

练习六

public class threadTest6 extends Thread{
    //创建一个静态的奖池
     static   ArrayList<Integer> list = new ArrayList<>();
    //给静态奖池赋值
    static {
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
    }
    //用于存储每个线程的获取的数据
    ArrayList<Integer> arr = new ArrayList<>();
    //锁
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        Random r = new Random();
        while (true){
//            //使抽奖更加均衡
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //上锁
            lock.lock();
            try {
                //判断奖池中是否还有数据
                if (list.size()==0){
                    break;
                }else {
                    //定义随机数抽取数据
                    int i = r.nextInt(list.size());
                    //将数据打印
//                    System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
                    arr.add(list.get(i));
                    //在list中删除该数据
                    list.remove(i);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        lock.lock();
        try {
            //执行完后调用输出
//            System.out.println(getName()+arr.toString());
            //整理各个线程的数据
            getdata(arr);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }

    private void getdata(ArrayList<Integer> arr) {
        System.out.println("在本次抽奖时,"+getName()+"共产生了"+arr.size()+"个奖项");
        System.out.print("分别为");
        for (int i = 0; i < arr.size(); i++) {
            if (i == arr.size()-1){
                System.out.print(arr.get(i));
            }else {
                System.out.print(arr.get(i)+", ");
            }
        }
        int max = arr.get(0);
        int sum = 0;

        for (int i = 0; i < arr.size(); i++) {
            sum = sum+arr.get(i);
            if (arr.get(i)>max){
                max = arr.get(i);
            }
        }
        System.out.println("最高金额为"+max+"元,总金额为"+sum+"元");
    }
}
public class Test6 {
    public static void main(String[] args) {
        threadTest6 t1 = new threadTest6();
        threadTest6 t2 = new threadTest6();

        t1.setName("抽奖箱一");
        t2.setName("抽奖箱二");

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

练习七

public class threadTest7 extends Thread{
    //创建一个静态的奖池
     static   ArrayList<Integer> list = new ArrayList<>();
    //给静态奖池赋值
    static {
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
    }
    //用于存储每个线程的获取的数据
    ArrayList<Integer> arr = new ArrayList<>();
    //锁
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        Random r = new Random();
        while (true){
//            //使抽奖更加均衡
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //上锁
            lock.lock();
            try {
                //判断奖池中是否还有数据
                if (list.size()==0){
                    break;
                }else {
                    //定义随机数抽取数据
                    int i = r.nextInt(list.size());
                    //将数据打印
//                    System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
                    arr.add(list.get(i));
                    //在list中删除该数据
                    list.remove(i);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        lock.lock();
        try {
            //执行完后调用输出
//            System.out.println(getName()+arr.toString());
            //整理各个线程的数据
            getdata(arr);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }

    public ArrayList<Integer> data(){
        return arr;
    }

    private void getdata(ArrayList<Integer> arr) {
        System.out.println("在本次抽奖时,"+getName()+"共产生了"+arr.size()+"个奖项");
        System.out.print("分别为");
        for (int i = 0; i < arr.size(); i++) {
            if (i == arr.size()-1){
                System.out.print(arr.get(i));
            }else {
                System.out.print(arr.get(i)+", ");
            }
        }
        int max = arr.get(0);
        int sum = 0;

        for (int i = 0; i < arr.size(); i++) {
            sum = sum+arr.get(i);
            if (arr.get(i)>max){
                max = arr.get(i);
            }
        }
        System.out.println("最高金额为"+max+"元,总金额为"+sum+"元");
    }
}
public class Test7 {
    public static void main(String[] args) throws InterruptedException {
        threadTest7 t1 = new threadTest7();
        threadTest7 t2 = new threadTest7();

        t1.setName("抽奖箱一");
        t2.setName("抽奖箱二");

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

        //将这两个线程插入main线程之前,即只有这两个线程执行完毕,数据集合中有数据了在执行下面的data方法
        t1.join();
        t2.join();

        ArrayList<Integer> data1 = t1.data();
        ArrayList<Integer> data2 = t2.data();
        //处理数据
        //获取各种的最大值
        int max1 = data1.get(0);
        int max2 = data2.get(0);
        for (Integer i : data1) {
            if (i>max1){
                max1 = i;
            }
        }
        for (Integer i : data2) {
            if (i>max2){
                max2 = i;
            }
        }
        //比较两个最大值
        if (max1>max2){
            System.out.println("本次抽奖中,"+t1.getName()+"获取最大奖项,该奖项金额为"+max1);
        }else {
            System.out.println("本次抽奖中,"+t2.getName()+"获取最大奖项,该奖项金额为"+max2);
        }
//
//        System.out.println(data1.toString());
//        System.out.println(data2.toString());
    }
}

讲解方法 

public class Test7_2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        thread7_2 t1 = new thread7_2();
        thread7_2 t2 = new thread7_2();

        //创建FutureTask的对象(用于管理多线程运行的结果)
        FutureTask<Integer> futureTask1 = new FutureTask<>(t1);
        FutureTask<Integer> futureTask2 = new FutureTask<>(t2);

        Thread th1 = new Thread(futureTask1);
        Thread th2 = new Thread(futureTask2);

        th1.setName("抽奖箱一");
        th2.setName("抽奖箱二");

        th1.start();
        th2.start();

        Integer i1 = futureTask1.get();
        Integer i2 = futureTask2.get();

        System.out.println("=====================");
        System.out.println(i1);
        System.out.println(i2);

        if (i1>i2){
            System.out.println(th1.getName()+"有最大金额"+i1);
        }else {
            System.out.println(th2.getName()+"有最大金额"+i2);
        }
    }
}
public class thread7_2 implements Callable<Integer> {
    //创建一个静态的奖池
    static ArrayList<Integer> list = new ArrayList<>();
    //给静态奖池赋值
    static {
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
    }

    @Override
    public Integer call() throws Exception {
        //用于存储每个线程的获取的数据
        ArrayList<Integer> arr = new ArrayList<>();
        Random r = new Random();
        while (true){
            synchronized (thread7_2.class){
                //判断奖池中是否还有数据
                if (list.size()==0){
                    break;
                }else {
                    //定义随机数抽取数据
                    int i = r.nextInt(list.size());
                    //将数据打印
//                    System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
                    arr.add(list.get(i));
                    //在list中删除该数据
                    list.remove(i);
                }
            }
        }
        synchronized (thread7_2.class){
            getdata(arr);
        }
        return Collections.max(arr);
    }

    private void getdata(ArrayList<Integer> arr) {
        System.out.println("在本次抽奖时,"+Thread.currentThread().getName()+"共产生了"+arr.size()+"个奖项");
        System.out.print("分别为");
        for (int i = 0; i < arr.size(); i++) {
            if (i == arr.size()-1){
                System.out.print(arr.get(i));
            }else {
                System.out.print(arr.get(i)+", ");
            }
        }
        int max = arr.get(0);
        int sum = 0;

        for (int i = 0; i < arr.size(); i++) {
            sum = sum+arr.get(i);
            if (arr.get(i)>max){
                max = arr.get(i);
            }
        }
        System.out.println("最高金额为"+max+"元,总金额为"+sum+"元");
    }
}

 

练习八

线程池

之前多线程代码的弊端

线程池

实现

public class Test {
    public static void main(String[] args) {
        //创建一个线程池对象
//        ExecutorService exe = Executors.newCachedThreadPool();
        //限制线程的数量为三,超出的任务只能等待
        ExecutorService exe = Executors.newFixedThreadPool(3);
        //向线程池对象中提交任务
        exe.submit(new threaddemo1());
        exe.submit(new threaddemo1());
        exe.submit(new threaddemo1());
        exe.submit(new threaddemo1());
        exe.submit(new threaddemo1());

        //销毁线程池
        exe.shutdown();
    }
}
public class threaddemo1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"===="+i);
        }
    }
}

自定义线程池

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

    /*
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
        (核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);

        参数一:核心线程数量              不能小于0
        参数二:最大线程数                不能小于0,最大数量 >= 核心线程数量
        参数三:空闲线程最大存活时间       不能小于0
        参数四:时间单位                  用TimeUnit指定
        参数五:任务队列                  不能为null
        参数六:创建线程工厂              不能为null
        参数七:任务的拒绝策略             不能为null
    */

        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,  //核心线程数量,能小于0
                6,  //最大线程数,不能小于0,最大数量 >= 核心线程数量
                60,//空闲线程最大存活时间
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(3),//任务队列
                Executors.defaultThreadFactory(),//创建线程工厂
                new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
        );



    }
}

线程池的最大

最大并行数

8即是最大并行数,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2163732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度知识追踪(论文复现)

深度知识追踪&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 文章目录 深度知识追踪&#xff08;论文复现&#xff09;论文概述论文方法实验部分数据集实验步骤step1:安装环境依赖step2:下载数据集&#xff0c;将其变成one-hot编码step3:进行训练…

备战软考Day04-计算机网络

1、计算机网络的分类 2、七层网络体系结构 3、网络的设备与标准 4、TCP/IP协议族 TCP/IP作为Internet的核心协议&#xff0c;被广泛应用于局域网和广域网中&#xff0c;目前已成为事实上的国际标准 1、TCP/IP分层模型 TCP/IP协议是Internet的基础和核心&#xff0c;和OSI参考…

SqlSugar的where条件中使用可空类型报语法错误

SQLServer数据表中有两列可空列&#xff0c;均为数值类型&#xff0c;同时在数据库中录入测试数据&#xff0c;Age和Height列均部分有值。   使用SqlSugar的DbFirst功能生成数据库表类&#xff0c;其中Age、Height属性均为可空类型。   当Where函数中的检索条件较多时&a…

Web3技术在元宇宙中的应用:从区块链到智能合约

随着元宇宙的兴起&#xff0c;Web3技术正逐渐成为其基础&#xff0c;推动着数字空间的重塑。元宇宙不仅是一个虚拟世界&#xff0c;它还代表着一个由去中心化技术驱动的新生态系统。在这个系统中&#xff0c;区块链和智能合约发挥着至关重要的作用&#xff0c;为用户提供安全、…

cefsharp新版本OnBeforeResourceLoad 禁止http自动跳转https显示404错误解决办法 含代码

一、问题 因项目需要,域名没有ssl证书,结果http访问时被强制定向到https前缀,结果会显示404 测试版本cefsharp126.x (x64) 框架 CefSharp.WinForms.NETCore 二、代码(核心代码) 如果请求url是http,且目标是https时,则阻止请求 //判断请求变化 if (url.StartsWith(<…

[linux 驱动]regmap子系统详解与实战

目录 1 描述 2 结构体 2.1 regmap 2.2 regmap_bus 2.3 regmap_config 3 regmap 操作函数 3.1 regmap 申请与初始化 3.1.1 regmap_init_i2c 3.1.2 regmap_init_spi 3.1.3 regmap_exit 3.2 regmap 设备访问 API 函数 3.2.1 regmap_read 3.2.2 regmap_write 4 示例 1…

如何在NXP源码基础上适配ELF 1开发板的UART功能

UART即通用异步收发器&#xff0c;是一种支持全双工串行通信协议的接口。在i.MX6ULL处理器平台上&#xff0c;该处理器原生支持多达8路的UART接口&#xff0c;提供了丰富的串行通信能力。 针对ELF 1开发板&#xff0c;实际引出了4路UART接口供开发者使用&#xff0c;具体包括U…

艾默生电源维修ASTEC电源模块MP4-2Q-1E-4EE-0N

Emerson/ASTEC电源模块维修-艾默生/雅达电源维修MP1,MP4,MP6,MP8系列型号。 电源维修中&#xff0c;许多电源采用UC38系列8脚PWM组件&#xff0c;大多数电源不能工作都是因为电源启动电阻损坏&#xff0c;或芯片性能下降。当R断路后无VC&#xff0c;PWM组件无法工作&#xff0…

实现领域驱动设计(DDD)系列详解:集成限界上下文

一个项目中通常存在着多个限界上下文&#xff0c;并且我们需要在它们之间进行集成。 在上下文映射图中存在两种主要形式&#xff1a;一种是通过绘制一些简单的框图来展示它们之间的集成关系&#xff1b;另一种则是通过代码来实现这些集成关系。 到了具体的技术实现&#xff0…

重学SpringBoot3-自定义starter

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-自定义starter 1. 什么是 Spring Boot Starter&#xff1f;Starter 的优势 2. Spring Boot 3 中的改进3. 常见的 Starter 示例3.1. 使用 Web Starter 构…

华硕主板开启TPM 2.0

安装Windows11系统&#xff0c;需要打开TPM 安装 Windows 11 的方法 电脑健康状况检查应用验证最低系统要求 在电脑上启用 TPM 2.0 查看主板型号 winr msinfo32 查看 tpm 进入Advanced Mode&#xff08;F7&#xff09; 选择Security&#xff0c;进入Secure Boot&#xff0c;我…

echarts横向柱状图让Y轴的名字和数量在柱状图上方展示

效果图 let vm thisvm.chart2 echarts.init(this.$refs.chart2)let xDatas this.registerProjectType.map((item) > {let found data.find((countItem) > countItem.projectType item.label)return found ? found.count : 0})// 翻转数据让其他项目在最下面let xDa…

现场扫码实时投票打分显示最新现场大屏微信现场投票实时显示

现场投票“神器”超级好玩儿||现场参与者通过手机扫码进入投票系统&#xff0c;大屏幕实时显示投票排名&#xff0c;增加紧张和刺激感。可以随时截止投票&#xff0c;方便便捷&#xff0c;可设置 单票&#xff0c;多票&#xff0c;自由票&#xff0c;结合现场互动&#xff0c;增…

SEO全自动发布外链工具增加权重的网站工具源码系统 带源代码包以及搭建部署教程

系统概述 传统的手动发布外链方式不仅费时费力&#xff0c;而且效率低下。因此&#xff0c;开发一款能够全自动发布外链的工具成为了迫切的需求。SEO 全自动发布外链工具增加权重的网站工具源码系统正是在这样的背景下诞生的。它旨在为网站管理员提供一种便捷、高效的方式来增…

图论系列(dfs)9.25

一、主题空间 场地由若干主题空间与走廊组成&#xff0c;场地的地图记作由一维字符串型数组 grid&#xff0c;字符串中仅包含 "0"&#xff5e;"5" 这 6 个字符。地图上每一个字符代表面积为 1 的区域&#xff0c;其中 "0" 表示走廊&#xff0…

B站批量删除动态—Python

B站协议批量删除动态实现 b站登录协议请看点方蓝色字体 b站扫码登录协议 文章结尾附Python代码 一、抓包 1.1删除动态包 POST请求 https://api.bilibili.com/x/dynamic/feed/operate/remove?platformweb&csrf3bdb2bda73e3d6f75ea991167fb39389 请求表单数据{&quo…

基于python+django+vue的电影数据分析及可视化系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

exebios提取工具通用exebios分离工具exe转编程器bios文件软件bios文件解密提取工具exe原厂bios提取烧录器bios芯片文件工具

好多电脑官网下载的BIOS文件是exe格式的特别是笔记本电脑&#xff0c;自己把电脑bios刷坏了黑屏不开机&#xff0c;需要用编程器刷BIOS&#xff0c;自然需要编程器版本的BIOS文件 需要把exe格式的BIOS文件转换成bin格式的编程器版本BIOS文件&#xff0c;转换需要用到一个小工具…

RAG技术全面解析:Langchain4j如何实现智能问答的跨越式进化?

LLM 的知识仅限于其训练数据。如希望使 LLM 了解特定领域的知识或专有数据&#xff0c;可&#xff1a; 使用本节介绍的 RAG 使用你的数据对 LLM 进行微调 结合使用 RAG 和微调 1 啥是 RAG&#xff1f; RAG 是一种在将提示词发送给 LLM 之前&#xff0c;从你的数据中找到并…

企业图纸文档管理系统推荐 三大企业图纸文档管理软件详细介绍

在现代企业的设计和生产过程中&#xff0c;图纸文档的管理是至关重要的一环。 无论是建筑、制造业&#xff0c;还是技术研发领域&#xff0c;图纸文档的正确存储、分享与管理能够极大提升工作效率&#xff0c;避免误操作或信息丢失。 接下来&#xff0c;小编将为大家推荐三款优…