多线程基础知识

多线程

基本概念

         线程:线程是操作系统能够进行运行调度的最小单位,它被包含在进程中,是进程中的实际运作单位     简单理解:应用软件中互相独立,可以同时运行的功能

         进程:进程是操作系统进行资源分配的单位

         并发:在同一时刻,有多个指令在单个CPU上交替执行

         并行:在同一时刻,有多个指令在多个CPU上同时执行

应用场景:

        软件中的耗时操作,后台服务器等

多线程的实现方式:

        继承Thread类的方式进行实现:

        

package com.lazyGirl.threaddemo;

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + " i=" + i);
        }
    }
}
package com.lazyGirl.threaddemo;

public class Test1 {
    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        ThreadDemo threadDemo1 = new ThreadDemo();
        
        threadDemo.setName("线程1");
        threadDemo1.setName("线程2");
        
        threadDemo.start();
        threadDemo1.start();
    }
}

输出:

        实现Runnable接口的方式进行实现:

        

package com.lazyGirl.threaddemo;

public class RunnableDemo implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {

            System.out.println(Thread.currentThread().getName() + " i:" + i );
        }
    }
}
package com.lazyGirl.threaddemo;

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

        RunnableDemo rd = new RunnableDemo();
        Thread t1 = new Thread(rd);
        Thread t2 = new Thread(rd);

        t1.setName("线程1");
        t2.setName("线程2");

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

输出:

        利用Callable接口和Future接口方式实现:

         可以获取多线程运行的结果

        步骤:

                创建一个类实现Callable接口,MyCallable

                重写Call方法(有返回值,表示多线程运行的结果)

                创建MyCallable对象(表示多线程要执行的任务)

                创建FutureTask的对象(管理多线程运行的结果)

                创建Thread类的对象,并启动(表示线程)

        

package com.lazyGirl.threaddemo;

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

public class Test3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CallableDemo callableDemo = new CallableDemo();
        FutureTask<Integer> futureTask = new FutureTask<>(callableDemo);
        new Thread(futureTask).start();
        System.out.println(futureTask.get());

    }
}

package com.lazyGirl.threaddemo;

import java.util.concurrent.Callable;

public class CallableDemo implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }
}

输出: 

对比: 

 

                        图来自黑马程序员网课 

常见成员方法:

                图来自黑马程序员网课  

抢占式调度:随机

Java中线程优先级为1-10,1最小,10最大,默认为5

线程的生命周期:

                        图来自黑马程序员 

线程安全问题:

package com.lazyGirl.threaddemo;

public class ThreadDemo2 extends Thread {

    static int ticket = 0;

    @Override
    public void run() {
        while (true) {
            if (ticket < 100){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                ticket++;
                System.out.println(getName() + " ticket is " + ticket);
            }else {
                break;
            }
        }
    }
}
package com.lazyGirl.threaddemo;

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


        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        ThreadDemo2 threadDemo3 = new ThreadDemo2();
        ThreadDemo2 threadDemo4 = new ThreadDemo2();

        threadDemo2.setName("窗口1");
        threadDemo3.setName("窗口2");
        threadDemo4.setName("窗口3");

        threadDemo2.start();
        threadDemo3.start();
        threadDemo4.start();
    }
}

输出: 

解决方式:

同步代码块:

        把操作共享数据的代码锁起来

        

                                图来自黑马程序员网课 

package com.lazyGirl.threaddemo;

public class ThreadDemo2 extends Thread {

    static int ticket = 0;

    static Object lock = new Object();
    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                if (ticket < 100){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    ticket++;
                    System.out.println(getName() + " ticket is " + ticket);
                }else {
                    break;
                }
            }
        }
    }
}

输出:

锁对象要唯一

 

它是唯一的 

同步方法:

        把synchronized关键字加到方法上

        

                                图来自黑马程序员网课 

package com.lazyGirl.threaddemo;

public class MyRunable implements Runnable{

    int ticket = 0;

    @Override
    public void run() {
        while(true){

            if (extracted()) break;
        }
    }

    private synchronized boolean extracted() {
        if (ticket == 100) {
            return true;
        }else {
            ticket++;
            System.out.println(Thread.currentThread().getName() + " ticket is " + ticket);
        }
        return false;
    }
}

输出:

StringBuilder的实例是不安全的,如果需要这样的同步,则使用StringBuffer

锁: 

         void lock():获得锁

         void unlock():释放锁

         

        图来自黑马程序员网课 

package com.lazyGirl.threaddemo;

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

public class ThreadDemo2 extends Thread {

    static int ticket = 0;
    static Lock lock = new ReentrantLock();

//    static Object lock = new Object();
    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {

                if (ticket == 100) {
                    break;
                }else {
                    Thread.sleep(10);
                    ticket++;
                    System.out.println(getName() + " " + ticket);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }



    }
}

输出:

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

常见方法:

                        图来自黑马程序员网课

 吃货代码:

package com.lazyGirl.waitandnotify;

public class Foodie extends Thread{

    @Override
    public void run() {

        while(true){
            synchronized(Desk.lock){
                if (Desk.count == 0){
                    break;
                }else {
                    if (Desk.foodFlag == 0){
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else {
                        Desk.count--;
                        System.out.println("吃货在吃面条,还能再吃 " + Desk.count + "碗");
                        Desk.lock.notify();
                        Desk.foodFlag = 0;
                    }
                }
            }
        }

    }
}

厨师代码:

package com.lazyGirl.waitandnotify;

public class Cook extends Thread {

    @Override
    public void run() {
        while (true){
            synchronized (Desk.lock) {
                if (Desk.count == 0){
                    break;
                }else {
                    if (Desk.foodFlag == 1){
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else {

                        System.out.println("厨师做饭");
                        Desk.foodFlag = 1;
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

测试类:

package com.lazyGirl.waitandnotify;

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

        Cook c = new Cook();
        Foodie f = new Foodie();

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

        c.start();
        f.start();

    }
}

 输出:

 等待唤醒机制(阻塞队列方式实现)

 阻塞队列的继承结构:

                                        图来自黑马程序员网课 

package com.lazyGirl.waitandnotifydemo2;

import java.util.concurrent.ArrayBlockingQueue;

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("noodle");
                System.out.println("厨师放了一碗面条");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }


    }
}
package com.lazyGirl.waitandnotifydemo2;

import java.util.concurrent.ArrayBlockingQueue;

public class Foodie extends Thread{

    ArrayBlockingQueue<String> queue;

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

    @Override
    public void run() {
        while (true){
            try {
                String food = queue.take();
                System.out.println(food);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
package com.lazyGirl.waitandnotifydemo2;

import java.util.concurrent.ArrayBlockingQueue;

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

        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

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

        c.start();
        f.start();
    }
}

 

线程的状态:

                                        图来自黑马程序员网课 

                                          图来自黑马程序员网课 

Case1:

        抢红包:

        

package com.lazyGirl.waitandnotifydemo2.Test4case1;

import java.util.Random;

public class Test extends  Thread{

    static double money = 100;
    static int count = 3;
    static final  double MIN = 0.01;

    @Override
    public void run() {

        synchronized (Test.class) {
            if (count == 0) {
                System.out.println(getName() + "没有抢到红包");
            }else {
                double prize = 0;
                if (count == 1) {
                    prize = money;
                }else {
                    Random random = new Random();
                    double bounds = money - (count -1) * MIN;
                    prize = random.nextDouble(bounds);
                    if (prize < MIN) {
                        prize = MIN;
                    }
                }
                money -= prize;
                count--;
                System.out.println(getName() + "抢到了 " + prize + "元");
            }
        }

    }

}
package com.lazyGirl.waitandnotifydemo2.Test4case1;

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

        Test t1 = new Test();
        Test t2 = new Test();
        Test t3 = new Test();
        Test t4 = new Test();
        Test t5 = new Test();


        t1.setName("h");
        t2.setName("hh");
        t3.setName("hhh");
        t4.setName("hhhh");
        t5.setName("hhhhh");

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

    }
}

        输出:

         内存分析

                        图来自黑马程序员网课 

package com.lazyGirl.waitandnotifydemo2.test7case;

import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {

    ArrayList<Integer> list;

    public MyCallable(ArrayList<Integer> list){
        this.list = list;
    }



    @Override
    public Integer call() throws Exception {
        ArrayList<Integer> boxList = new ArrayList<>();
        while(true){

            Thread.sleep(10);

            synchronized (MyCallable.class){
                if (list.size() == 0){

                    System.out.println(Thread.currentThread().getName() + boxList);
                    break;
                }else {
                    Collections.shuffle(list);
                    int prize = list.remove(0);
//                    System.out.println(getName() + "又产生了一个" + prize + "元大奖");
                    boxList.add(prize);
                }

            }
        }
        if (boxList.size() == 0){
            return null;
        }else {
            return Collections.max(boxList);
        }
    }
}

package com.lazyGirl.waitandnotifydemo2.test7case;


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

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,20,30,40,50);

        //创建多线程要运行的参数对象
        MyCallable t = new MyCallable(list);

        //创建多线程运行结果的管理者对象
        FutureTask<Integer> ft1 = new FutureTask<>(t);
        FutureTask<Integer> ft2 = new FutureTask<>(t);

        Thread t1 = new Thread(ft1);
        Thread t2 = new Thread(ft2);

        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");


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

        Integer max1 = ft1.get();
        Integer max2 = ft2.get();

        System.out.println(max1);
        System.out.println(max2);

        if (max1 > max2){
            System.out.println(t1.getName() + "获得" + max1 + "大奖");
        }else if (max1 < max2){
            System.out.println(t1.getName() + "获得" + max2 + "大奖");
        }


    }
}

输出:

线程池: 

核心原理:

 1)创建一个池子,池子中是空的

 2)提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可

 3)所有任务全部执行完毕,关闭线程池

代码实现:

 Executors:线程池的工具类通过调用方法返回不同类型的线程池对象

                        图来自黑马程序员网课 

package com.lazyGirl.threadpooldemo;

public class MyRunnable implements Runnable {
    @Override
    public void run() {

//        for (int i = 0; i < 10; i++) {
//            System.out.println(Thread.currentThread().getName() + ":" + i);
//        }

        System.out.println(Thread.currentThread().getName());


    }
}
package com.lazyGirl.threadpooldemo;

import java.lang.reflect.Executable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService pool1 = Executors.newFixedThreadPool(3);


        pool1.submit(new MyRunnable());
        Thread.sleep(1000);
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());

        pool1.shutdown();

    }
}

输出:

 自定义线程池:

                                图来自黑马程序员网课  

                               图来自黑马程序员网课   

线程池大小:

        CPU密集型运算: 最大并行数 + 1

        I/O密集型运算: 最大并行数 * 期望CPU利用率 *(总时间(CPU计算时间 + 等待时间)/ CPU计算时间)

                                                 图来自黑马程序员网课   

         

 

相关推荐

  1. C++11线基本知识

    2024-06-18 14:12:01       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-18 14:12:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-18 14:12:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-18 14:12:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-18 14:12:01       18 阅读

热门阅读

  1. 生产环境下部署微调的10条戒律

    2024-06-18 14:12:01       6 阅读
  2. 常用原语介绍

    2024-06-18 14:12:01       8 阅读
  3. Redis内存数据库

    2024-06-18 14:12:01       5 阅读
  4. 【React】useState 的原理

    2024-06-18 14:12:01       7 阅读
  5. 【go】go初始化命令总结

    2024-06-18 14:12:01       6 阅读
  6. 【大数据】gRPC、Flink、Kafka 分别是什么?

    2024-06-18 14:12:01       6 阅读
  7. C#面:请说说C#引用和对象?

    2024-06-18 14:12:01       5 阅读