首页 > 编程语言 >javaseday31多线程

javaseday31多线程

时间:2024-09-26 19:50:13浏览次数:11  
标签:线程 Thread class public static new 多线程 javaseday31

什么是多线程

线程与进程

小结

并发和并行

并发

并行

小结 

多线程的实现方式

方法一

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即是最大并行数,

标签:线程,Thread,class,public,static,new,多线程,javaseday31
From: https://blog.csdn.net/m0_72625929/article/details/142448621

相关文章

  • .NetCore MySqlException 多线程中(There is already an open DataReader associated w
    问题描述:其实标题只是遇到问题的其中之一,遇到三种异常信息如下:Lockwaittimeoutexceeded;tryrestartingtransaction大概意思:超过锁定等待超时;尝试重新启动事务 ThereisalreadyanopenDataReaderassociatedwiththisConnectionwhichmustbeclosedfirst.大......
  • 多线程极速导出/9字段10W行只需2秒/导入导出打印组件/功能丰富简单易用
    一、功能特点组件同时集成了导出数据到csv、xls、pdf和打印数据。所有操作全部提供静态方法无需new,数据和属性等各种参数设置采用结构体数据,极为方便。同时支持QTableView、QTableWidget、QStandardItemModel、QSqlTableModel等数据源。提供静态方法直接传入QTableView、QTab......
  • Redis6 多线程模型
    优质博文:IT-BLOG-CN一、单线程的优缺点对于一个请求操作Redis主要做3件事情:从客户端读取数据/解析、执行Redis命令、回写数据给客户端。所以主线程其实就是把所有操作的这3件事情串行一起执行,因为是基于内存,所以执行速度非常快。优点&缺点:【1】优点:不存在锁的竞争问题和......
  • 银行存取款多线程
    importjava.util.Random;importjava.lang.*;/***银行存取款**@authorLaccoliths*/publicclassBank{privateintcount=0;/***存钱*@parammoney:存钱数*/publicsynchronizedvoidaddMoney(intmoney){count+......
  • Linux 基础入门操作 第十章 多线程实现
    10线程介绍线程是进程的一条执行路径。每个线程共享其所附属的进程的所有的资源,包括打开的文件、页表(因此也就共享整个用户态地址空间)、信号标识及动态分配的内存等等。线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一物理内存空间......
  • 【Linux】多线程:线程池的创建、日志类、RAII互斥锁、单例模式:饿汉方式与懒汉方式
    目录一、线程池概念二、线程的封装及线程池类成员变量的介绍 三、单例模式饿汉方式(EagerInitialization)懒汉方式(LazyInitialization)四、RAII类型的互斥锁 五、日志类的实现六、简单的任务类创建七、线程池的创建 一、线程池概念线程池(ThreadPool)是一种基于......
  • JavaEE——多线程
    接着上篇博客我们已经学习了进程的相关概念,了解到进程里面的相关重要属性,那么这篇博客呢我们要学习一个新的知识点——线程!一、引入进程的目的首先引入进程这个概念,是为了解决“并发编程”这样的问题。因为CPU再往小了做,比较困难了,这是因为CPU进入了多核心的时代,要想进一......
  • JavaEE——多线程Thread 类及常见方法
    目录 一、Thread(Stringname)二、是否后台线程isDeamon()三、是否存活isAlive()四、run()方法和start()方法的区别五、中断线程法一:法二:六、线程等待join()七、线程休眠sleep()一、Thread(Stringname)定义:这个东西是给线程(thread对象)起一个名字。起一个......
  • Java多线程
    文章目录前言1实现多线程1.1多线程概述1.2多线程的实现方式1.3线程休眠1.4线程优先级1.5守护线程2线程同步2.1同步代码块2.2Lock锁2.3死锁3生产者消费者3.1生产者和消费者模式概述3.2阻塞队列基本使用3.3阻塞队列实现等待唤醒机制前言"劝君莫惜金......
  • 万象更新 Html5 - h5: h5 通过 web worker 实现多线程
    源码https://github.com/webabcd/Html5作者webabcd万象更新Html5-h5:h5通过webworker实现多线程示例如下:h5\webWorker\worker.html<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>通过web......