2022-3-18-多线程

本文探讨了多线程的概念,包括并发、并行的定义,并详细阐述了进程与线程的区别。通过Java实例,展示了Thread、Runnable和Callable的使用方式,以及线程池的应用。同时,分析了多线程的优缺点,如提高CPU利用率但可能引发资源竞争和死锁问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程:在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理“。

并发(Concurrent):同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

并行(Parallel):当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。其实决定并行的因素不是CPU的数量,而是CPU的核心数量,比如一个CPU多个核也可以并行。

进程(Process):是正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说CPU(寄存器),IO,内存,网络资源等。同样一个程序,同一时刻被两次运行了,那么他们就是两个独立的进程。

线程(Thread):是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

进程与线程的区别:

  • 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;进程是系统资源分配的单位,线程是系统调度的单位。
  • 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
  • 进程之间相互独立,进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。同时线程还有自己的栈和栈指针,程序计数器等寄存器。
  • 调度和切换:线程上下文切换比进程上下文切换要快得多。

 多线程优缺点

优点:

(1) 用户界面可以在进行其它工作的同时CPU一直处于活动状态,可以让程序运行速度更快。

(2)占用大量处理时间的任务可以定期将处理器时间让给其它任务,可以提高CPU利用率。

缺点:

(1)等候使用共享资源时造成程序的运行速度变慢。这些共享资源主要是独占性的资源 ,如打印机等。

(2)对线程进行管理要求额外的 CPU开销,线程的使用会给系统带来上下文切换的额外负担。

(3)线程的死锁。即对共享资源加锁实现同步的过程中可能会死锁

Thread:

package com.qyq.test.demo01;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <=20 ; i++) {
//            System.out.println("com.qyq.test.dome01:"+i);
            //获取到当前线程的名字
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName+": "+i);
        }
    }
}

Thread的测试类:

package com.qyq.test.demo01;

public class TestThread {
    public static void main(String[] args) {
        //new 线程
        MyThread myThread = new MyThread();
        //开启线程
        myThread.start();
        for (int i = 1; i <= 20; i++) {
            System.out.println("mian线程"+i);
        }
    }
}

使用Thread写三个人同时卖票小案例(三个人各自卖各自的票)

package com.qyq.test.demo02;
// 三个人同时卖票(各自卖各自的)
public class TicketThread extends Thread {
    private  String name;
    private  int ticket =10;


    public TicketThread(String name){
        this.name=name;
    }

//    public TicketThread(String name) {
//        super(name);
//    }

    @Override
    public void run() {

//        for (int i = 0; i < ticket; i++) {
//            System.out.println( Thread.currentThread().getName()+"卖掉一张票剩余:"+i+"张");
//        }
        while (ticket>0){
            try {
                //设值休眠时间
                sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
//            System.out.println(Thread.currentThread().getName()+"卖掉一张票,剩余"+--ticket);
            System.out.println(name+"卖掉一张票,剩余"+--ticket);
        }
    }

    public static void main(String[] args) {
        TicketThread ticketThread1 =new TicketThread("时军涛");
        TicketThread ticketThread2 =new TicketThread("aaa");
        ticketThread1.start();
        ticketThread2.start();

    }
}

Runnable 练习小案例 (俩人共卖10张票)

Runnable类:

package com.qyq.test.demo03;

public class RunnableTest {
    public static void main(String[] args) {
        Ticket ticket =new Ticket();
        Thread thread1 = new Thread(ticket, "aaa");
        Thread thread2 = new Thread(ticket, "bbb");

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

测试类:

package com.qyq.test.demo03;

public class Ticket implements Runnable{
    //票数
    private int ticket = 10;
    @Override
    public void run() {
        while (ticket>0){
            System.out.println(Thread.currentThread().getName()+"卖掉一张票,剩余:"+--ticket);
        }
    }
}

 callable 练习:

        callable有两种实现方法:

1.使用FutureTasshi

2.使用线程池

package com.qyq.test.demo05;

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

//callable可以有返回值,也可以抛出异常的特性
public class CallableTest implements Callable {
    @Override
    public Object call() throws Exception {
        //执行线程业务的方法
        for (int i = 0; i < 10; i++) {
            //返回正在执行的线程实例
            System.out.println(Thread.currentThread().getName()+"执行打印"+i);
        }
        //获取随机数
        UUID uuid = UUID.randomUUID();
        System.out.println("随机数字字符串为:"+uuid);
        return uuid;
    }

    public static void main(String[] args) {
        //Callable的两种执行方式:
        
        //1.
        CallableTest callableTest = new CallableTest();

        //使用FutureTask包装类
        FutureTask futureTask = new FutureTask<>(callableTest);

        //包装为Thread
        Thread thread = new Thread(futureTask);
        thread.start();

/**
        //2.
        CallableTest callableTest = new CallableTest();
        //创建一个线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future future = executorService.submit(callableTest);
//        这个接口实现的线程,是有返回值的
 */
    }
}

线程池练习: 

ExecutorService executorService = Executors.newFixedThreadPool(设值线程最大并行数);
package com.qyq.test.demo06;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 6; i++) {
            System.out.println(Thread.currentThread().getName()+"执行打印"+i);
        }
    }

    public static void main(String[] args) {
        //实例化线程类
        ThreadPool threadPool = new ThreadPool();
        ThreadPool threadPool2 = new ThreadPool();
        ThreadPool threadPool3 = new ThreadPool();
        ThreadPool threadPool4 = new ThreadPool();

        //使用Executors创建固定长度为4的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //调用exectorService启动线程
        executorService.execute(threadPool);
        executorService.execute(threadPool2);
        executorService.execute(threadPool3);
        executorService.execute(threadPool4);
    }
}

多线程匿名(Anonymous)内部类用法:

package com.qyq.test.demo07;

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

public class AnonymityThread {
    public static void main(String[] args) {
        //继承Thread启用线程
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    //返回正在执行的线程实力
                    //getName() 获取当前线程实例的名称
                    System.out.println(Thread.currentThread().getName()+"执行打印"+i);
                }
            }
        }.start();

        System.out.println("--------------------------");

        //实现Runnable接口
      new Thread(new Runnable() {
          @Override
          public void run() {
              for (int i = 0; i < 3; i++) {
                  //返回正在执行的线程实力
                  //getName() 获取当前线程实例的名称
                  System.out.println(Thread.currentThread().getName()+"执行打印"+i);
              }
          }
      }).start();

        System.out.println("--------------------------");


        //实现callable接口
        new Thread(new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                for (int i = 0; i < 3; i++) {
                    //返回正在执行的线程实力
                    //getName() 获取当前线程实例的名称
                    System.out.println(Thread.currentThread().getName()+"执行打印"+i);
                }
                return "callable可以抛异常可以返回值";
            }
        })).start();

    }
}

 线程优先级:“理论优先!!! ”

这是个玄学问题是真的理论优先!!!

package com.qyq.test.demo08;

public class PriorityThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName()+"执行线程"+i);
        }
    }

    public static void main(String[] args) {
        PriorityThread priorityThread = new PriorityThread();
        Thread thread1 = new Thread(priorityThread, "a");
        Thread thread2 = new Thread(priorityThread, "b");
        Thread thread3 = new Thread(priorityThread, "c");

        thread1.setPriority(10);
        thread2.setPriority(5);
        thread3.setPriority(1);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值