day_20~21:多线程

一、什么是进程?

  进程是系统进行资源分配和调度的独立单元,每一个进程都有它的“独立”内存空间和系统资源。

二、单进程操作系统和多进程操作系统的区别

  单进程操作系统(DOS):一次只能执行一个进程

  单用户多进程操作系统(Windows):一次可以执行多个进程

  多用户多进程操作系统(Linux、Unix):一次可以执行多个进程

三、现在的多核CPU是否可以让系统在同一时刻可以执行多个任务呢?

  理论上是绝对可以的,实际上发生这种情况较少。

四、什么是线程,理解线程和进程的关系

  线程是进程里面的一条执行路径,每个线程共享进程里面的内存空间和系统资源

五、我们应用的软件有哪些是多线程的应用?

  基本上都是多线程(因为现在用户体验要求越来越高)

六、Java中,如何来编写一个多线程的应用?

  1、线程类:创建一个类,继承Thread,重写run方法 ------ new MyThread().start()

  2、任务类:创建一个类,实现Runnable接口里面的run方法 ------ new Thread(new Task())

  3、带有返回值的任务类。

    主线路从上往下,多线程多条执行路线(随机)

public class MyThread extends Thread{
    
    @Override
    public void run() {//编写当前线程的功能
        System.out.println("创建线程类多线程");
    }
}




public class Test01 {

    public static void main(String[] args) {
        //创建线程类的对象
        MyThread thread = new MyThread();
        //启动线程:thread线程抢到资源后才能运行run方法
        thread.start();
    }
}
线程类
//任务类
public class Task implements Runnable{
    
    @Override
    public void run() {
        System.out.println("任务类多线程");
    }
}



public class Test02 {
    public static void main(String[] args) {
        //创建线程对象,并把任务交给他
        Thread thread = new Thread(new Task());
        //启动线程
        thread.start();
    }
}
任务类
public class PTest01 {

    public static void main(String[] args) {

        //创建并启动子线程
        new MyThread1().start();
        
        for (int i = 1; i <= 200; i++) {
            System.out.println(i);
        }
    }

}

class MyThread1 extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 200; i++) {
            System.out.println(i);
        }
    }
}
应用

  经典面试题:请问当我们编写一个单纯的main方法时,此时该程序是否为单线程的?为什么?

    是多线程程序,因为后台有一个守护线程叫做垃圾回收器(线程)。在后台默默守护着非守护线程,等到非守护线程全部消亡时,守护线程会自动消亡

七、线程的优先级

  优先级别从大到小:10 --1

  设置优先级别会让概率变大一些

public class Test01 {

    public static void main(String[] args) {
        /**
         * 练习:在主线程中创建两个以上的子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。
         */
        
        A a = new A();
        B b = new B();
        C c = new C();
        
        //设置优先级别
        a.setPriority(Thread.MAX_PRIORITY);
        b.setPriority(Thread.NORM_PRIORITY);
        c.setPriority(Thread.MIN_PRIORITY);
        
        a.start();
        b.start();
        c.start();
    }
}
class A extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("a:" + i);
        }
    }
}
class B extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("b:" + i);
        }
    }
}
class C extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("c:" + i);
        }
    }
}
测试优先级

八、给线程自定义名称

public class Test02 {

    public static void main(String[] args) {
//        MyThread thread = new MyThread("线程1");
//        MyThread thread2 = new MyThread("线程2");
        MyThread thread = new MyThread();
        MyThread thread2 = new MyThread();
        thread.setThreadName("线程1");
        thread2.setThreadName("线程2");
        thread.start();
        thread2.start();
    }
}

class MyThread extends Thread {

    private String threadName;

    public MyThread() {
    }

    public MyThread(String threadName) {
        this.threadName = threadName;
    }

    public String getThreadName() {
        return threadName;
    }

    public void setThreadName(String threadName) {
        this.threadName = threadName;
    }

    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            System.out.println(threadName + " -- " + i);
        }
    }
}
给进程自定义名字
public class Test01 {

    public static void main(String[] args) {
        
        /**
         * 给线程自定义名称
         */
        MyThread t1 = new MyThread("线程1");
        MyThread t2 = new MyThread("线程2");
        
        //调用父类设置名字的方法
//        t1.setName("线程1");
//        t2.setName("线程2");
        
        t1.start();
        t2.start();
    }
}
class MyThread extends Thread{
    
    public MyThread() {
    }
    
    public MyThread(String threaName) {
        super(threaName);//把名字传给父类了
    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            
//            Thread thread = Thread.currentThread();//获取当先线程的对象
//            String name = thread.getName();//获得当前线程对象的名字
            
            System.out.println(Thread.currentThread().getName() + " -- " + i);
        }
    }
}
super()把名字传给父类

九、让线程休眠

public class Test {

    public static void main(String[] args) throws InterruptedException {
        /**
         * 练习:编写一个抽取学员回答问题的程序,要求倒数三秒后输出被抽中的学员姓名
         */
        String[] names = new String[] { "赤名莉香", "关口里美", "长崎尚子", "周芷若", "郑强", "和贺夏树" };
        Random ran = new Random();
        for (int i = 3; i > 0; i--) {
            System.out.println(i);
            Thread.sleep(1000);
        }
        System.out.println(names[ran.nextInt(names.length)]);
    }
}
倒数三秒后输出被抽中的学员姓名

Thread.sleep()是静态,当前方法写在哪个线程里,哪个线程就休眠

十、线程的礼让

public class Test01 {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();

        a.start();
        b.start();
    }

}

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

}

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

}
线程礼让

yeild()礼让:是静态,当前方法写在哪个线程里,哪个线程就礼让,礼让是退出资源,然后再次进入到抢资源的状态

十一、线程的合并

主线程和子线程同时运行,满足一定条件后,让子线程先运行至结束

public class Test01 {
    
    public static void main(String[] args) throws InterruptedException {
        
        /**
         * 练习:主线程和子线程各打印200次,从1开始每次增加1,当主线程打印到10之后,
         *              让子线程先打印完再打印主线程
         */
        
        MyTread t1 = new MyTread();
        t1.start();
        
        for (int i = 1; i <= 200; i++) {
            System.out.println("主线程:" + i);
            if(i == 10){
                //把子线程合并
                t1.join();
            }
        }
    }
}
class MyTread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 200; i++) {
            System.out.println("子线程:" + i);
        }
    }
}
主线程和子线程合并
public class Test02 {

    public static void main(String[] args) {

        /**
         * A线程和B线程各打印200次,从1开始每次增加1,当A线程打印到10之后, 让B线程先打印完再打印A线程
         */
        B b = new B();

        A a = new A(b);

        a.start();
        b.start();

    }
}

class A extends Thread {
    private B b;

    public A(B b) {
        this.b = b;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 200; i++) {
            if (i == 10) {
                try {
                    b.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("A" + i);
        }
    }
}

class B extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 200; i++) {
            System.out.println("B" + i);
        }
    }
}
两个子线程合并

join()合并:写在哪个线程里,就合并到哪个线程

十二、线程的中断

public class Test01 {

    public static void main(String[] args) throws Exception {
        MyThread thread = new MyThread();
        thread.start();
        Thread.sleep(3000);
        thread.setFlag(false);
    }

}

class MyThread extends Thread {

    private boolean flag = true;

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

    @Override
    public void run() {

        while (flag) {
            System.out.println("怒发冲冠凭阑处。。。");
        }
    }
}
线程中断
public class Test02 {

    public static void main(String[] args) throws Exception {
        MyThread1 myThread1 = new MyThread1();
        myThread1.start();
        Thread.sleep(3000);
        //改变线程状态
        myThread1.interrupt();
    }

}

class MyThread1 extends Thread {
    @Override
    public void run() {
        // 判断当前线程是否已中断
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("壮志饥餐胡虏肉。。。");
        }
    }
}
改变线程状态中断线程

十三、线程局部变量(实现线程范围内的共享变量)

public class Test01 {
    
    public static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

    public static void main(String[] args) {

        //线程1
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 10;
                Test01.map.put(Thread.currentThread().getName(), i);//存入数据
                new A().print();//Thread-0 -- A类 -- 10
                new B().print();//Thread-0 -- B类 -- 10
            }
        }).start();

        //线程2
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 20;
                Test01.map.put(Thread.currentThread().getName(), i);//存入数据
                new A().print();//Thread-1 -- A类 -- 20
                new B().print();//Thread-1 -- B类 -- 20
            }
        }).start();
    }
}
class A{
    public void print(){
        String name = Thread.currentThread().getName();
        Integer value = Test01.map.get(name);
        
        System.out.println(name + " -- A类 -- " + value);
    }
}
class B{
    public void print(){
        String name = Thread.currentThread().getName();
        Integer value = Test01.map.get(name);
        
        System.out.println(name + " -- B类 -- " + value);
    }
}
Map实现 -- 自定义值
public class Data {
    private String name;
    private int age;

    public Data() {
    }

    public Data(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Data [name=" + name + ", age=" + age + "]";
    }

}





public class Test002 {

    public static ConcurrentHashMap<String, Data> map = new ConcurrentHashMap<>();

    public static void main(String[] args) {

        // 线程1
        new Thread(new Runnable() {

            @Override
            public void run() {
                Test002.map.put(Thread.currentThread().getName(), new Data("赤名莉香", 18));
                new C().print();// Thread-0 -- A类 -- Data [name=赤名莉香, age=18]
                new D().print();// Thread-0 -- B类 -- Data [name=赤名莉香, age=18]
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                Test002.map.put(Thread.currentThread().getName(), new Data("郑强", 1314));
                new C().print();// Thread-1 -- A类 -- Data [name=郑强, age=1314]
                new D().print();// Thread-1 -- B类 -- Data [name=郑强, age=1314]

            }
        }).start();
    }
}

class C {
    public void print() {
        String name = Thread.currentThread().getName();
        Data value = Test002.map.get(name);
        System.out.println(name + " -- A类 -- " + value);
    }
}

class D {
    public void print() {
        String name = Thread.currentThread().getName();
        Data value = Test002.map.get(name);
        System.out.println(name + " -- B类 -- " + value);
    }
}
Map实现 -- 传入对象
public class Data2 {
    private String name;
    private int age;

    public Data2() {
    }

    public Data2(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Data2 getInstance(String name, int age) {
        Data2 data = Test0003.local.get();
        if (data == null) {
            data = new Data2(name, age);
        } else {
            data.setName(name);
            data.setAge(age);
        }
        return data;

    }

    @Override
    public String toString() {
        return "Data [name=" + name + ", age=" + age + "]";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}



public class Test0003 {

    public static ThreadLocal<Data2> local = new ThreadLocal<>();

    public static void main(String[] args) {

        // 线程1
        new Thread(new Runnable() {

            @Override
            public void run() {
                Test0003.local.set(new Data2("赤名莉香", 18));
                new E().print();// Thread-0 -- A类 -- Data [name=赤名莉香, age=18]
                new F().print();// Thread-0 -- B类 -- Data [name=赤名莉香, age=18]
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                Test0003.local.set(new Data2("郑强", 1314));
                new E().print();// Thread-1 -- A类 -- Data [name=郑强, age=1314]
                new F().print();// Thread-1 -- B类 -- Data [name=郑强, age=1314]

            }
        }).start();
    }
}

class E {
    public void print() {
        String name = Thread.currentThread().getName();
        Data2 value = Test0003.local.get();
        System.out.println(name + " -- A类 -- " + value);
    }
}

class F {
    public void print() {
        String name = Thread.currentThread().getName();
        Data2 value = Test0003.local.get();
        System.out.println(name + " -- B类 -- " + value);
    }
}
使用ThreadLocal实现

A) 实现单个数据共享

    B) 实现多个数据共享--打包成实体类

    C) 类似于单例模式的数据共享

十四、线程的生命周期

注意:

  进程与进程:独享内存空间和系统资源

  同一个进程里的多个线程:共享聂村空间和系统资源

  一个进程里可以有多个线程:多个线程不同的执行路径(不同的功能)

  一个进程里只能有一个主线程

十五、作业

 1、计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。

public class test01 {
    public static void main(String[] args) throws Exception {
        /**
         * 计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
         */
        int[] nums = new int[20000];
        for (int i = 0; i < nums.length; i++) {
            nums[i] = i;
        }

        MyThread t1 = new MyThread(nums, 0, 5000);
        MyThread t2 = new MyThread(nums, 5000, 10000);
        MyThread t3 = new MyThread(nums, 10000, 15000);
        MyThread t4 = new MyThread(nums, 15000, 20000);

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

        t1.join();
        t2.join();
        t3.join();
        t4.join();

        System.out.println(t1.getNum() + t2.getNum() + t3.getNum() + t4.getNum());
    }
}

class MyThread extends Thread {
    private int[] nums;
    private int startIndex;
    private int endIndex;
    private int num;

    public MyThread(int[] nums, int startIndex, int endIndex) {
        this.nums = nums;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    @Override
    public void run() {
        for (int i = startIndex; i < endIndex; i++) {
            num += nums[i];
        }
    }

    public int getNum() {
        return num;
    }

}
还可以用任务类做

2、采用多线程技术,改造之前的断点续传的案例,实现多线程断点续传,要求线程的数量可由客户端程序来设置,实现思路如下:根据线程的数量,将文件分成多段,每个线程负责其中一段的拷贝工作

public class Test02 {

    public static void main(String[] args) {
        /**
         * 采用多线程技术,改造之前的断点续传的案例,实现多线程断点续传, 要求线程的数量可由客户端程序来设置,实现思路如下:
         * 根据线程的数量,将文件分成多段,每个线程负责其中一段的拷贝工作
         */

        System.out.println("请输入想分几段来完成拷贝:");
        Scanner scan = new Scanner(System.in);
        int lenNum = scan.nextInt();
        File file = new File("上原亚衣.avi");
        long fileLen = file.length();
        long foreLen = fileLen / lenNum;
        long lastName = fileLen / lenNum + fileLen % lenNum;

        for (int i = 0; i < lenNum - 1; i++) {
            new YouThread(file, foreLen, foreLen * i).start();
        }
        new YouThread(file, lastName, foreLen * (lenNum - 1)).start();
        scan.close();
    }
}

class YouThread extends Thread {
    private File file;
    private long length;
    private long startIndex;

    public YouThread(File file, long length, long startIndex) {
        this.file = file;
        this.length = length;
        this.startIndex = startIndex;
    }

    @Override
    public void run() {
        RandomAccessFile r = null;
        RandomAccessFile w = null;
        try {
            r = new RandomAccessFile(file, "r");
            w = new RandomAccessFile("copy.avi", "rw");

            r.seek(startIndex);
            w.seek(startIndex);

            byte[] bys = new byte[1024];
            int len;
            long num = 0;
            while ((len = r.read(bys)) != -1) {
                w.write(bys, 0, len);
                num += len;
                if (num >= length) {
                    break;
                }
            }

        } catch (Exception e) {
        } finally {
            try {
                r.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                w.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
续传

3、铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售

public class Test01 {

    public static void main(String[] args) {
        /**
         * 需求:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售, 请编写多线程程序来模拟这个效果
         * 
         * 问题一:三个线程各卖了1000张票 解决:三个线程共用同一个任务类的对象,并且把ticket变成全局变量
         * 
         * 问题二:有一些票卖重了 解决:卖票的打印语句必须和票的自减一起运行完毕,才能退出系统资源
         * 
         * 问题三:卖负票 解决:在锁里再加个判断
         * 
         * synchronized --- 互斥锁、同步锁: 锁对象:多个线程之间必须共用同一把锁对象,才能互相排斥
         * 
         * 同步代码块: synchronized(锁对象){ ......... }
         * 
         * 同步方法: public synchronized void method02(){}
         * 
         * 锁对象为:this
         * 
         * Lock锁: 锁对象就是本身
         * 
         * synchronized vs Lock 答:Lock锁可以实现synchronized锁的所有功能,但是Lock锁必须手动解锁
         */

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

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

}

class Task implements Runnable {

    int ticket = 1000;//
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        // while (ticket > 0) {
        // method02();
        // }

        method03();

    }

    private void method03() {
        while (ticket > 0) {
            lock.lock();
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
                ticket--;
                if (ticket == 0) {
                    System.out.println(Thread.currentThread().getName() + "销售完了");
                }
            } else {
                System.out.println(Thread.currentThread().getName() + "销售完了");
            }
            lock.unlock();
        }
    }

    // 同步方法:锁对象--this
    private synchronized void method02() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
            ticket--;
            if (ticket == 0) {
                System.out.println(Thread.currentThread().getName() + "票已经售完");
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "票已经售完");
        }
    }

    // 同步代码块实现
    private void nethod01() {
        while (ticket > 0) {
            synchronized (this) {
                method02();
            }
        }
    }
}
任务类
public class Test02 {

    public static void main(String[] args) {

        new MyThread("窗口1").start();
        new MyThread("窗口2").start();
        new MyThread("窗口3").start();
    }
}

class MyThread extends Thread {
    static int ticket = 1000;
    static Object obj = new Object();
    static Lock lock = new ReentrantLock();

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        // while (ticket > 0) {
        // method02();
        // }
        while (ticket > 0) {
            lock.lock();
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
                ticket--;
                if (ticket == 0) {
                    System.out.println(Thread.currentThread().getName() + "已经售完");

                }
            } else {
                System.out.println(Thread.currentThread().getName() + "已经售完");

            }
            lock.unlock();
        }
    }

    private static synchronized void method02() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
            ticket--;
            if (ticket == 0) {
                System.out.println(Thread.currentThread().getName() + "已经售完");

            }
        } else {
            System.out.println(Thread.currentThread().getName() + "已经售完");

        }
    }

    private void method01() {
        while (ticket > 0) {
            // synchronized ("123") {
            // synchronized (obj) {
            synchronized (String.class) {

                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
                    ticket--;
                    if (ticket == 0) {

                        System.out.println(Thread.currentThread().getName() + "已经售完");
                    }
                } else {
                    System.out.println(Thread.currentThread().getName() + "已经售完");
                }
            }
        }
    }
}
线程类

十六、多线程下的单例模式

/**
 * 多线程下的单例模式
 * 优点:效率高、不浪费资源、线程安全
 */
public class MyClass {

    private static MyClass my = null;
    
    private MyClass() {
    }
    
    public static MyClass getInstance(){
        
        if(my != null){
            return my;
        }
        
        synchronized ("123") {
            if(my == null){
                my = new MyClass();
            }
        }
        
        return my;
    }
    
    public static void print(){
        System.out.println("夏凡你是最胖的...");
    }
}
多线程下的单例模式

十七、死锁

public class Test01 {
    
    public static void main(String[] args) {
        
        //死锁案例:
        //1.编写多线程时,一定要多分析
        //2.锁里再放锁,容易造成死锁
        
        new MyThread(true).start();
        new MyThread(false).start();
    }
}
class MyThread extends Thread{
    
    boolean flag;
    
    public MyThread(boolean flag) {
        this.flag = flag;
    }
    
    @Override
    public void run() {
        
        if(flag){
            synchronized (KuaiZi.a) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                synchronized (KuaiZi.b) {
                    System.out.println("哲学家1 --- 吃饭了");
                }
            }
        }else{
            synchronized (KuaiZi.b) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                synchronized (KuaiZi.a) {
                    System.out.println("哲学家2 --- 吃饭了");
                }
            }
        }
    }
}

class KuaiZi{
    public static Object a = new Object();
    public static Object b = new Object();
}
死锁

如果出现同步嵌套(同步里面包含同步),就有可能会产生死锁问题  

只有对方都拥有了彼此的资源且不愿意释放时,才会出现死锁问题

十八、线程池

//线程池底层实现
public class ThreadPool {
    private ArrayList<MyThread> list = new ArrayList<>();
    private int index = 0;

    public ThreadPool(int threadNum) {
        for (int i = 0; i < threadNum; i++) {
            MyThread thread = new MyThread("pool - thread -" + i);
            list.add(thread);
        }
    }

    private class MyThread extends Thread {
        public MyThread(String name) {
            super(name);
        }
    }
}
线程池底层实现
public class Test01 {
    public static void main(String[] args) {
        // 创建只有一个线程的线程池
        ExecutorService pool = Executors.newSingleThreadExecutor();
        // 创建指定线程个数的线程池
        ExecutorService pool1 = Executors.newFixedThreadPool(2);
        // 创建带有缓冲的线程池
        ExecutorService pool2 = Executors.newCachedThreadPool();

        // 提交任务
        pool2.submit(new Task());
        pool2.submit(new Task());
        pool2.submit(new Task());
        pool2.submit(new Task());

        // 关闭线程池
        pool.shutdown();
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println(Thread.currentThread().getName() + "-----" + i);
        }
    }
}
线程池的应用

带有返回值的任务类 + 线程池的使用

需求:计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。

public class Test01 {
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        /**
         * 需求:计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
         */
        int[] is = new int[20000];
        for (int i = 0; i < is.length; i++) {
            is[i] = (i+1);
        }
        
        ExecutorService pool = Executors.newFixedThreadPool(4);
        
        //提交带有返回值的任务类,执行完毕后会把任务类的返回值放在Futuer对象中
        //注意submit是线程阻塞的方法
        Future<Integer> s1 = pool.submit(new Task(is, 0, 5000));
        Future<Integer> s2 = pool.submit(new Task(is, 5000, 10000));
        Future<Integer> s3 = pool.submit(new Task(is, 10000, 15000));
        Future<Integer> s4 = pool.submit(new Task(is, 15000, 20000));
        
        //获取对象中的数据并求和
        System.out.println(s1.get() + s2.get() + s3.get() + s4.get());
        
        pool.shutdown();
    }
}
class Task implements Callable<Integer>{
    
    private int[] is;
    private int startIndex;
    private int endIndex;
    
    public Task(int[] is, int startIndex, int endIndex) {
        this.is = is;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    //类似于Runnable接口里的run方法
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = startIndex; i < endIndex; i++) {
            sum += is[i];
        }
        return sum;
    }
    
}
应用

十九、生产者消费者模型

与之前多线程卖票的区别:

案例:(生产手机、消费手机)

public class Phone {
    private String name;
    private double price;
    private boolean store;

    public Phone() {
    }

    public Phone(String name, double price, boolean store) {
        this.name = name;
        this.price = price;
        this.store = store;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public boolean isStore() {
        return store;
    }

    public void setStore(boolean store) {
        this.store = store;
    }

    @Override
    public String toString() {
        return "Phone [name=" + name + ", price=" + price + ", store=" + store + "]";
    }

}
Phone.java
public class Producer extends Thread {

    private Phone phone;
    private static boolean bool = true;// 如果是多个对象的话应该放在这里并用static修饰

    public Producer(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (phone) {
                while (phone.isStore()) {// 如果是单个生产者对象的话,用if
                    try {
                        phone.wait();
                    } catch (InterruptedException e) {
                    }
                }
                if (bool) {
                    phone.setName("赤名莉香");
                    phone.setPrice(1314);
                } else {
                    phone.setName("郑强");
                    phone.setPrice(520);
                }
                bool = !bool;
                phone.setStore(true);
                // 唤醒
                phone.notifyAll();// 如果是单个生产者对象的话,唤醒就用phone.notify()

            }
        }
    }
}




public class Consumer extends Thread {
    private Phone phone;

    public Consumer(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (phone) {
                while (!phone.isStore()) {
                    try {
                        phone.wait();
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println(phone.getName() + "  *** " + phone.getPrice());
                phone.setStore(false);
                phone.notifyAll();
            }
        }
    }
}
producer、consumer
public class Test01 {

    public static void main(String[] args) {
        Phone phone = new Phone();
        Producer p1 = new Producer(phone);
        Producer p2 = new Producer(phone);
        Consumer c1 = new Consumer(phone);
        Consumer c2 = new Consumer(phone);

        p1.start();
        p2.start();
        c1.start();
        c2.start();
    }

}
Test

仓储模型

//仓库
public class Store {

    private int max = 20;// 仓库最大容量
    private int num = 0;// 仓库现在库存量

    // 入库
    public void push() {

        synchronized (this) {
            if (num >= max) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                }
            }
            num++;
            System.out.println("入库,库存量:" + num);
            this.notify();
        }
    }

    // 出库
    public void pop() {
        synchronized (this) {
            if (num <= 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                }
            }
            num--;
            System.out.println("出库,库存量:" + num);
            this.notify();
        }
    }
}
Store
public class Producer extends Thread {
    private Store store;

    public Producer(Store store) {
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            store.push();
        }
    }
}



public class Consumer extends Thread {
    private Store store;

    public Consumer(Store store) {
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            store.pop();
        }
    }
}
Producer、Consumer
public class Test {

    public static void main(String[] args) {

        Store store = new Store();

        Producer p = new Producer(store);
        Consumer c = new Consumer(store);

        p.start();
        c.start();

    }

}
Test

当有多个生产者和消费者时改动跟上面一样改。( if 改为 while、this.notify 改为 this.notifyAll )

 十九、作业

public class Cake implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 7087277041944375330L;
    private String name;
    private String date;

    public Cake() {
    }

    public Cake(String name, String date) {
        this.name = name;
        this.date = date;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Cake [name=" + name + ", date=" + date + "]";
    }
}
Cake
public class Producer extends Thread {
    private Store store;

    public Producer(Store store,String name) {
        super(name);
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            store.push();
            try {
                sleep(2000);
            } catch (InterruptedException e) {
            }
        }
    }
}





public class Consumer extends Thread {
    private Store store;

    public Consumer(Store store,String name) {
        super(name);
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            store.pop();
            try {
                sleep(2000);
            } catch (InterruptedException e) {
            }
        }
    }
}
Producer、Consumer
//仓库
public class Store {
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public LinkedList<Cake> cakes = new LinkedList<>();
    private int num = 0;
    private int max = 20;
    private String name;
    private String date;

    public void push() {

        synchronized (this) {
            while (cakes.size() == max) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                }
            }
            num++;
            name = "cake" + String.valueOf(num);
            date = sdf.format(new Date());
            Cake cake = new Cake(name, date);
            cakes.add(cake);
            System.out.println(Thread.currentThread().getName() + " -- " + "制作蛋糕:" + cake);
            this.notifyAll();

        }
    }

    public void pop() {
        synchronized (this) {

            while (cakes.size() == 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                }
            }
            // try {
            // Thread.sleep(2000);
            // } catch (InterruptedException e) {
            // }
            num--;
            // Cake removeFirst = cakes.removeFirst();
            System.out.println(Thread.currentThread().getName() + " -- " + "购买蛋糕:" + cakes.removeFirst());
            this.notifyAll();
        }
    }
}
Store
public class Test {

    public static void main(String[] args) {
        /**
         * 有一个蛋糕店,最大库存数可以存储20个蛋糕,有5个生产师傅不断生产,有5个顾客不断的买,
         * 生产一个蛋糕需要2秒,卖出的蛋糕必须按照时间顺序,卖最早生产的蛋糕
         */

        Store store = new Store();

        Producer p1 = new Producer(store,"生产者1");
        Producer p2 = new Producer(store,"生产者2");
        Producer p3 = new Producer(store,"生产者3");
        Producer p4 = new Producer(store,"生产者4");
        Producer p5 = new Producer(store,"生产者5");
        Consumer c1 = new Consumer(store,"消费者1");
        Consumer c2 = new Consumer(store,"消费者2");
        Consumer c3 = new Consumer(store,"消费者3");
        Consumer c4 = new Consumer(store,"消费者4");
        Consumer c5 = new Consumer(store,"消费者5");

        p1.start();
        p2.start();
        p3.start();
        p4.start();
        p5.start();
        c1.start();
        c2.start();
        c3.start();
        c4.start();
        c5.start();

    }

}
Test

 

 

 

 

 

posted @ 2018-11-09 17:59  cmlx  阅读(175)  评论(0)    收藏  举报