Java多线程学习笔记

Java多线程学习笔记

1.程序:一段静态的代码。
进程:程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程,有它自身的产生,存在和消亡的过程。
线程:进程可进一步细化为线程,是程序内部的一个执行路径。

2.线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc)。 一个进程可能有多个线程,多个线程共享相同的内存单元,如图,方法区内是 static的静态方法,堆内是 创建的对象。
在这里插入图片描述
3. 一个进程的多个线程共享相同的内存单元,从一个堆中分配对象,可以访问相同的变量和对象,这就使得线程之间的通信更加简便高效。但多个线程操作共享的系统资源可能会带来安全隐患。

4.单核CPU:假多线程,即在一个时间单元内,只执行了一个线程的任务。例如:一个厨师同时做多个菜,只能分配给每一道菜部分时间,最后完成。 因为CPU的时间单元很短,因此感觉不到。

  1. 一个Java应程序java.exe,至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。

6.并行与并发
并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。
并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀,多个人做一件事。

7.线程创建方式一

package com.meiya.java;

/**
 * 多线程创建 方式1:继承Thread类
 * 步骤:
 *      1. 创建一个继承于Thread类的子类
 *      2. 重写Thread类的run()方法 --将此线程执行的操作声明在run中
 *      3. 创建Thread类的子类的对象
 *      4. 通过此对象调用start() 方法
 *
 *  eg: 遍历100以内的偶数
 *
 */

// 1. 创建一个继承于Thread类的子类
    class MyThread extends Thread{
        // 2. 重写Thread类的run()方法
        public void run(){
            for (int i = 0; i < 10000; i++) {
                if (i % 2 == 0){
                    System.out.println(Thread.currentThread().getName() + i);
                }
            }
        }
}


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

        // 3. 创建Thread类的子类的对象 alt+enter
        MyThread myThread = new MyThread();

        // 4. 通过此对象调用start() 方法 :1.启动当前线程 2.调用当前的run方法
        myThread.start();

        // 问题1:如果不通过start 直接调用run ,run会执行,但不会新建一个线程,操作还是main主线程实现
        // myThread.run()

        // 问题2:不可以让 已经start的线程再去start(即同一个thread),会报异常 IllegalThreadStateException
        // myThread.start();
        // 需要重新创建一个Thread对象 start
        MyThread myThread1 = new MyThread();
        myThread1.start();

        for (int i = 0; i <10000 ; i++) {
            System.out.println(Thread.currentThread().getName() + i);
        }

    }

}

8.线程常用方法

package com.meiya.java;

/**
 *
 * 测试 Thread 中的 常用方法:
 * 1. start():启动当前线程;调用当前线程的run()
 * 2. run(): 通常需要重写Thread 类中的此方法,将创建的线程要执行的操作声明在此方法中
 * 3. currentThread():静态方法,返回执行当前代码的线程
 * 4. getName(): 获取当前线程的名字
 * 5. setName(): 设置当前线程的名字
 * 6. yield(): 释放当前cpu的执行权。当前排队的线程进行重新争夺cpu执行权。
 * 7. join(): 在线程a中调用线程b的join(),此时a线程进入到阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
 * 8. stop(): 已过时,当执行此方法时,强制结束当前线程。
 * 9. sleep(long millitime) : 让当前线程“睡眠” 指定的,millitime毫秒数,在指定的millitime毫秒时间内,
 *    线程是阻塞状态。
 * 10. isAlive() : 判断当前线程是否存活。
 *
 *
 * 线程的优先级:
 *  1. MAX_PRIORITY: 10
 *  2. MIN_PRIORITY: 1
 *  3. NORM_PRIORITY: 5  默认优先级
 *
 * 2.获取和设置当前线程的优先级
 *      getPriority: 获取线程的优先级
 *      setPriority(int i): 设置线程的优先级
 *
 * 说明:高优先级的线程要抢占低优先级线程的cpu的执行权,但是只是从概率上讲,
 * 高优先级更容易抢占到cpu的执行权,并不是只有高优先级执行完成,才执行低优先级。
 *
 *
 */

class ThreadByTest extends Thread{

    public void run(){

        System.out.println(Thread.currentThread().getName() + ":的优先级是" +Thread.currentThread().getPriority());
        for (int i = 0; i < 100 ; i++) {
            if(i % 2 ==0){
                System.out.println(Thread.currentThread().getName()+ ":" + i);
                try {
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

//            if(i % 20 ==0){
//                yield();
//            }

        }
    }
}

public class ThreadMethodTest {
    public static void main(String[] args) {
        ThreadByTest threadByTest = new ThreadByTest();
        threadByTest.setName("线程1");
        System.out.println(Thread.currentThread().getName() + ":的优先级是" +Thread.currentThread().getPriority());

        // 设置分线程的优先级
        //threadByTest.setPriority(10);

        threadByTest.start();

        // 给主线程命名
        Thread.currentThread().setName("主线程");

        for (int i = 0; i < 100 ; i++) {
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName()+ ":" + i);
            }

            if(i == 20 ){
                System.out.println(threadByTest.isAlive());
                try {
                    threadByTest.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }



    }
}


ps:
run()方法内使用sleep()需要try/catch,而不能采用直接Throws抛出,原因是Thread的run()方法没有抛出异常,因此继承Thread的子类不可以抛出比父类范围大的异常。

9.线程的调度
调度策略:
调度方法:
1.同优先级线程组成先进先出队列(先到先服务),使用时间片策略
2.对高优先级,使用优先调度抢占式策略

10.通过实现Runnable接口创建线程

package com.meiya.java;

/**
 *
 * 创建多线程的方式二: 实现Runnable接口
 * 1. 创建一个实现了Runnable接口的类
 * 2,实现类去实现Runnable 的抽象方法:run()
 * 3. 创建实现类的对象
 * 4.将此对象作为参数传递到Thread类的构造器中,创建Thread对象
 * 5.通过Thread类的对象调用start()
 *
 *
 * 比较创建线程的两种方式:
 *  开发中优先选择实现Runnable接口方式
 *  原因:1.单继承多实现,单继承有局限性,相对宝贵
 *       2.实现的方式更适合处理多个线程有共享数据的情况。
 *
 *  相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在Run()
 *         中
 */

// 1. 创建一个实现了Runnable接口的类
class ThreadRunnable implements Run nable {


    // 2,实现类去实现Runnable 的抽象方法:run()
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+ i);
        }
    }
}

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

        // 3. 创建实现类的对象
        ThreadRunnable threadRunnable = new ThreadRunnable();

        // 4.将此对象作为参数传递到Thread类的构造器中,创建Thread对象
        Thread thread = new Thread(threadRunnable);

        // 5.通过Thread类的对象调用start()
        thread.setName("线程1");
        thread.start();


        // 再创建一个线程
        Thread thread1 = new Thread(threadRunnable);
        thread1.setName("线程2");
        thread1.start();
    }
}

线程通信:wait() / notify() / notifyAll() : 此三个方法定义在Object类中。

线程分类:
Java中线程分为两类:一种是守护线程,一种是用户线程。
1.它们在几乎各个方面都是相同的,唯一区别是判断JVM何时离开。
2.守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true) 可以把一个用户线程变成一个守护线程。
3.Java垃圾回收就是一个典型的守护线程。
4.若JVM中都是守护线程,当前JVM将退出。

线程的生命周期
在这里插入图片描述

在这里插入图片描述
线程同步:
问题:如以上的卖票问题,在卖票的多线程程序执行中,出现了 重票,错票 ,的线程安全问题。
问题出现原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来。
如何解决:当一个线程a在操作共享资源(ticket)时候,其他线程不能参与进来,直到线程a操作完ticket时,其他线程才可以开始操作ticket,这种情况即使a线程进入阻塞状态,也不能被改变。

在Java中,我们通过同步机制,来解决线程安全的问题。

方式一:同步代码块
synchronized(同步监视器){
// 需要被同步的代码
}
说明: 1.操作共享数据的代码,即为需要被同步的代码
2.共享数据:多个线程共同操作的变量。如:ticket就是共享数据。
3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。
要求:多个线程必须要共用一把锁。

	 补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。		
package com.meiya.java;

/**
 *
 * 创建多线程的方式二: 实现Runnable接口
 * 1. 创建一个实现了Runnable接口的类
 * 2,实现类去实现Runnable 的抽象方法:run()
 * 3. 创建实现类的对象
 * 4.将此对象作为参数传递到Thread类的构造器中,创建Thread对象
 * 5.通过Thread类的对象调用start()
 *
 *
 * 比较创建线程的两种方式:
 *  开发中优先选择实现Runnable接口方式
 *  原因:1.单继承多实现,单继承有局限性,相对宝贵
 *       2.实现的方式更适合处理多个线程有共享数据的情况。
 *
 *  相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在Run()
 *         中
 *
 *  //  补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this 充当同步监视器。
 *         
 */

// 1. 创建一个实现了Runnable接口的类
class ThreadRunnable implements Runnable {

    private int ticket = 100;
    Object object = new Object();

    // 2,实现类去实现Runnable 的抽象方法:run()
    public void run() {

        while(true){
            synchronized (object){
                if(ticket > 0){
                    System.out.println(Thread.currentThread().getName() + ":票号为" + ticket);
                    ticket--;
                } else {
                    break;
                }
           }
        }
}
}

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

        // 3. 创建实现类的对象
        ThreadRunnable threadRunnable = new ThreadRunnable();

        // 4.将此对象作为参数传递到Thread类的构造器中,创建Thread对象
        Thread thread = new Thread(threadRunnable);

        // 5.通过Thread类的对象调用start()
        thread.setName("线程1");
        thread.start();


        // 再创建一个线程
        Thread thread1 = new Thread(threadRunnable);
        thread1.setName("线程2");
        thread1.start();
    }
}

方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

关于同步方法的总结:
1.同步方法仍然涉及到同步监视器,只是不需要我们显示的声明。
2.非静态的同步方法,同步监视器是:this
静态的同步方法,同步监视器是:当前类本身

package com.meiya.java;

import static java.lang.Thread.sleep;

/**
 *
 * 使用同步方法解决实现Runnable接口的线程安全问题
 *
 *
 */

class ThreadRunnable1 implements Runnable {

    private int ticket = 100;

    // 2,实现类去实现Runnable 的抽象方法:run()
    public void run() {

        while(true){
            show();

            }
        }

    private synchronized void show(){ //同步监视器 this
        if(ticket > 0){
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ":票号为" + ticket);
            ticket--;
        }
    }


    }


public class ThreadByTongBuMethod  {

    public static void main(String[] args) {
        // 3. 创建实现类的对象
        ThreadRunnable1 threadRunnable = new ThreadRunnable1();

        // 4.将此对象作为参数传递到Thread类的构造器中,创建Thread对象
        Thread thread = new Thread(threadRunnable);

        // 5.通过Thread类的对象调用start()
        thread.setName("线程1");
        thread.start();


        // 再创建一个线程
        Thread thread1 = new Thread(threadRunnable);
        thread1.setName("线程2");
        thread1.start();
    }


}

同步的优缺点:
1.同步的方式,解决了线程的安全问题。—好处
2.操作同步代码时,只有一个线程参与,其他线程等待,相当于一个单线程的过程,效率低。 —局限性(但必须接受)

线程的死锁问题
1.死锁
a.不同的线程分别占用对方需要的同步资源不放弃,都在等对方放弃自己需要的同步资源,就形成了线程的死锁。
b.出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。

2.解决办法
a.专门的算法,原则
b.尽量减少同步资源的定义
c.尽量避免嵌套同步

package com.meiya.java;

import static java.lang.Thread.sleep;


/**
 *
 * 线程的死锁问题
 * 1.死锁
 * 	a.不同的线程分别占用对方需要的同步资源不放弃,都在等对方放弃自己需要的同步资源,就形成了线程的死锁。
 * 	b.出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。
 *
 * 2. 说明
 * 1).出现死锁后,不会出现异常,不会出现提示,只是所有的下称都处于阻塞状态,无法继续
 * 2).我们使用同步时,要避免出现死锁。
 *
 */

public class DeadLockTest {


    public static void main(String[] args) {

        final StringBuffer stringBuffer1 = new StringBuffer();
        final StringBuffer stringBuffer2 = new StringBuffer();


        new Thread(){
            public void run(){

                synchronized (stringBuffer1){
                    stringBuffer1.append("a");
                    stringBuffer2.append("1");

                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (stringBuffer2){
                        stringBuffer1.append("b");
                        stringBuffer2.append("2");

                        System.out.println(stringBuffer1);
                        System.out.println(stringBuffer2);
                    }
                }
            }
        }.start();


        new Thread(new Runnable() {
            public void run() {

                synchronized (stringBuffer2){
                    stringBuffer1.append("a");
                    stringBuffer2.append("1");

                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (stringBuffer1){
                        stringBuffer1.append("b");
                        stringBuffer2.append("2");

                        System.out.println(stringBuffer1);
                        System.out.println(stringBuffer2);
                    }
                }
            }
        }).start();
    }
}

解决线程安全问题的方式三:Lock锁

package com.meiya.java;

import java.util.concurrent.locks.ReentrantLock;

import static java.lang.Thread.sleep;

/**
 *
 * 解决线程安全问题的方式三:Lock锁  --JDK5.0新增
 *
 * 1. 面试题:synchronized 与 lock 异同 ?
 *    同:  都是用来解决线程安全问题
 *    不同:synchronized在执行完同步代码块以后,自动释放同步监视器
 *         lock需要手动的启动同步(lock()),手动结束同步(unlock())
 *
 * 2.优先使用顺序
 * Lock -> 同步代码块(已经进入方法体,分配了相应 资源) -> 同步方法(在方法体之外)
 *
 * 3. 面试题:如何解决线程安全问题?有几种?
 *  1)synchronized 同步代码块,同步方法
 *  2)lock锁
 *
 *
 *
 */


class Window implements  Runnable{

    private int ticket = 100;

    // 实例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();

    public void run() {

        while (true) {

            try {

                // 调用锁定lock方法
                lock.lock();

                if(ticket > 0){

                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                    System.out.println(Thread.currentThread().getName()+":"+ticket);
                    ticket--;
                }else{
                    break;
                }
            }finally {

                // 调用解锁方法:unlock
                lock.unlock();

            }


        }

    }
}


public class LockTest {

    public static void main(String[] args) {
        Window window = new Window();
        Thread window1 = new Thread(window);
        Thread window2 = new Thread(window);
        Thread window3 = new Thread(window);

        window1.setName("窗口1");
        window2.setName("窗口2");
        window3.setName("窗口3");

        window1.start();
        window2.start();
        window3.start();

    }
}

线程通信案例

package com.meiya.java;


import static java.lang.Thread.sleep;

/**
 *
 * 线程通信的例子:是同两个线程打印1-100 ,线程1,线程2 交替打印
 *
 * 涉及到线程通信的3个方法:
 * wait(): 一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
 * notify(): 一旦执行此方法,就会唤醒被wait()的一个线程,如果多个线程被wait()就唤醒优先级高的。
 * notifyAll(): 一旦执行此方法,就会唤醒所有被wait()的线程。
 *
 * 说明:
 *  1.wait(),notify(),notifyAll() 必须使用在 同步代码块 或 同步方法 中。
 *  2.wait(),notify(),notifyAll() 调用者必须是同步代码块或同步方法的同步监视器。
 *      否则会出现IllegalMonitorStateException异常。
 *  3.wait(),notify(),notifyAll() 三个方法定义在java.lang.Object类中。
 *
 *
 *  面试题:sleep()和wait()方法异同?
 *  相同点:
 *      1.都会使线程进入阻塞状态
 *  不同点:
 *      1.两个方法声明的位置不同:Thread类中声明的sleep(),Object中声明wait()
 *      2.调用范围不同:sleep()可以在任何需要的场景下调用。wait()必须在同步代码块或同步方法中。
 *      2.关于是否释放同步监视器:sleep()不会交出同步监视器,wait()会交出同步监视器。
 */

class Number implements Runnable{

    private int number = 1;
    private Object object = new Object();


    public void run() {

        while (true){

            synchronized (object){

                object.notify();

                if(number <= 100){

                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()+":"+number);
                    number++;

                    try {
                        // 使得调用如下wait()方法的线程进入阻塞状态,并释放锁
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }


        }

    }
}

public class ThreadCommunicationTest {

    public static void main(String[] args) {

        Number number = new Number();

        Thread thread1 = new Thread(number);
        Thread thread2 = new Thread(number);
        thread1.setName("线程1");
        thread2.setName("线程2");

        thread1.start();
        thread2.start();

    }
}

线程通信经典案例:生产者,消费者,店员

package com.meiya.java;


import static java.lang.Thread.sleep;

/**
 *
 * 线程通信的应用:经典例题:生产者、消费者问题
 *
 * 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,
 * 店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫
 * 生产者停一下,如果店中有空位放产品再通知生产者继续生产;如果店里没有产品了,店员会
 * 告诉消费者等一下,如果店里有产品了再通知消费者来取走产品;
 *
 * 分析:
 * 1. 是否多线程问题?是 生产者线程,消费者线程
 * 2. 是否有共享数据?是,店员(产品)
 * 3. 如何解决线程安全问题? 同步机制
 * 4. 如何解决 等待操作: wait() notify()
 *
 */


// 生产者
class Product implements Runnable{

    private Clerk clerk;

    public Product(Clerk clerk) {
        this.clerk = clerk;
    }

    public void run() {

        System.out.println(Thread.currentThread().getName()  + ":开始生产产品...");

        while (true){

            synchronized (clerk){

                // 解除 正在wait的 消费者线程
                clerk.notify();

                // 产品数量低于20
                if(clerk.getProduct() <20){
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    // 生产者生产1件商品
                    clerk.setProduct(clerk.getProduct()+1);
                    System.out.println(Thread.currentThread().getName()  + ":生产1件产品,当前剩余产品"+clerk.getProduct());
                }else {   // 产品 >= 20 生产者停止生产,等待不足20时再被唤醒
                    try {
                        System.out.println(Thread.currentThread().getName()  + ":无法生产产品,当前产品已满,数量为:"+clerk.getProduct());
                        clerk.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }


        }
    }
}

// 消费者
class Customer implements Runnable{

    private Clerk clerk;

    public Customer(Clerk clerk) {
        this.clerk = clerk;
    }

    public void run() {

        System.out.println(Thread.currentThread().getName() + ":开始消费产品...");

        while (true){

            synchronized (clerk){

                // 解除 正在wait的 生产者线程
                clerk.notify();

                // 产品数量 >0
                if(clerk.getProduct() >0){
                    try {
                        sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    // 消费者消费1件产品
                    clerk.setProduct(clerk.getProduct()-1);
                    System.out.println(Thread.currentThread().getName()  + ":消费1件产品,当前剩余产品"+clerk.getProduct());
                }else {
                    try {
                        System.out.println(Thread.currentThread().getName()  + ":无法消费产品,当前产品已空,数量为:"+clerk.getProduct());

                        // 产品 <=0 消费者线程等待
                        clerk.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }


        }
    }
}

// 店员
class Clerk {

    // 产品数量
    private int product;

    public Clerk(int product) {
        this.product = product;
    }

    public int getProduct() {
        return product;
    }

    public void setProduct(int product) {
        this.product = product;
    }

}

public class ProductTest {

    public static void main(String[] args) {

        // 创建店员 产品数量为10
       Clerk clerk = new Clerk(10);

       // 创建生产者
       Product product = new Product(clerk);

        // 创建消费者
       Customer customer = new Customer(clerk);

        // 创建生产者线程
       Thread thread1 = new Thread(product);

        // 创建消费者线程
       Thread thread2 = new Thread(customer);

       thread1.setName("生产者");
       thread2.setName("消费者");

       // 开启  生产者线程
       thread1.start();

        // 开启 消费者线程
       thread2.start();


    }

}

创建线程的方式三:实现callable接口。-- JDK 5.0 新增

package com.meiya.java;


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

/**
 *
 * 创建线程的方式三:实现callable接口。-- JDK 5.0 新增
 *
 * 如何理解实现Callable接口的方式比实现Runnable接口创建多线程强大???
 *  1.call()可以有返回值。
 *  2.call()可以抛出异常,被外面的操作捕获,获取异常信息。
 *  3.Callable是支持泛型的。
 *
 *
 */

 // 1. 创建一个实现 Callable 的实现类
class NumThread implements Callable<Integer>{

    // 2. 重写Call() 方法,将此线程需要执行的操作声明在call() 中
    public Integer call() throws Exception {

        int sum = 0;

        for (int i = 1; i <= 100 ; i++) {
            if(i%2==0){
                System.out.println(i);
                sum+=i;
            }
        }

        return sum;
    }
}


public class ThreadByCallable {

    public static void main(String[] args) {

        // 3. 创建Callable接口实现类的对象
        NumThread numThread = new NumThread();

        // 4. 将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,用来接收 call() 的 返回值
        FutureTask objectFutureTask = new FutureTask(numThread);

        // 5. 将FutureTask的对象传递到Thread的构造器中
        Thread thread = new Thread(objectFutureTask);

        // 6. 调用start()方法
        thread.start();

        try {


            // 7. get方法返回值即为FutureTask构造器参数Callable实现类重写call()的返回值
            Object sum = objectFutureTask.get();

            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

创建线程的方式四:使用线程池。-- JDK 5.0 新增

**背景:**经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

**思路:**提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用。类似生活中的公共交通工具。

好处:
1.提高响应速度(减少了创建新线程的时间)
2.降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
3.便于管理线程

package com.meiya.java;


import java.util.concurrent.*;

/**
 *
 * 创建线程的方式四:使用线程池
 *
 * 好处:
 *      1.提高响应速度(减少了创建新线程的时间)
 * 		2.降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
 * 		3.便于管理线程
 * 	        corePoolSize : 核心池的大小
 * 	        maximumPoolSize: 最大线程数
 * 	        KeepAliveTime: 线程没有任务时最多保持多长时间后停止
 *          ...
 *
 *   面试题: 创建多线程几种方式? 4种
 *          
 */

class NumberThread implements Runnable{


    public void run() {
        for (int i = 0; i < 100 ; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":"+ i);
            }
        }
    }
}

class Number1Thread implements Runnable{


    public void run() {
        for (int i = 0; i < 100 ; i++) {
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":"+ i);
            }
        }
    }
}

class Number2Thread implements Callable{

    public Object call() throws Exception {

        int sum = 0;

        for (int i = 0; i < 100 ; i++) {

            if(i % 2 == 0){
                sum+=i;
            }
        }
        // System.out.println(Thread.currentThread().getName() + ":" + sum);

        return sum;
    }
}

public class ThreadByThreadPool {


    public static void main(String[] args) {

        // 1.提供指定线程数量的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor executorService1 = (ThreadPoolExecutor)executorService;

        // 设置线程池属性
        //System.out.println(executorService.getClass());
        executorService1.setCorePoolSize(15);


        // 2.执行指定的线程的操作,需要提供实现 Runnable接口 或 Callable接口 实现类的对象
        // executorService.execute() 适合使用于Runnable
        executorService.execute( new NumberThread());
        executorService.execute( new Number1Thread());



        // 适合使用于Callable
        Future future = executorService.submit(new Number2Thread());

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值