首页 > 其他分享 >多线程

多线程

时间:2024-03-11 23:23:15浏览次数:19  
标签:Thread System 线程 println new 多线程 public

多线程的实现

java.lang.Thread类代表多线程

注意事项

  • 启动线程必须是start方法,不是调用run方法
  • 不要把主线任务放在启动子线程之前

继承Thread

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 16:43
 */
public class MyThread extends Thread{
    @Override
    public void run() {
        ....
    }
}

优点:编码简单

缺点:线程类已经继承Thread,无法继承其他类,不利于功能扩展

实现Runable接口

import java.lang.management.RuntimeMXBean;

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 16:43
 */
public class MyThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("子线程" + i);
        }
    }
}
/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 16:50
 */
public class ThreadDemo {
    public static void main(String[] args) {
        Runnable myThread = new MyThread();
        new Thread(myThread).start();
        for (int i = 0; i < 10;i ++){
            System.out.println("主线程" + i);
        }
    }
}

优点:人物类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强

缺点:需要多一个Runnable对象

上述方法也可以使用匿名内部类实现

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 16:55
 */
public class ThreadDemo {
    public static void main(String[] args) {
        new Thread(()-> {
                for (int i = 0; i < 10; i++) {
                    System.out.println("子线程" + i);
                }
        }).start();
        for (int i = 0; i < 10; i++){
            System.out.println("主线程" + i);
        }
    }
}

实现Callable接口

这种线程创建方式最大的优点就是可以返回线程执行的结果。

  • 实现Callable接口
  • 重写call方法
import java.util.concurrent.Callable;

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 17:01
 */
public class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n){
        this.n = n;
    }
    @Override
    public String call() throws Exception {
        //描述现成的任务和返回线程执行后的结果
        int sum = 0;
        for (int i = 1; i <= n;i++){
            sum += i;
        }
        return "线程求出了1-"+n+"的和为:" + sum;
    }
}
  • 创建MyCallable对象
  • 创建FurtureTack对象
  • 创建线程并且Start
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 16:55
 */
public class ThreadDemo {
    public static void main(String[] args) {
        Callable<String> myCallable = new MyCallable(100);
        //未来任务对象是一个任务对象,实现了Runnable接口
        //可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕之后的结果
        final FutureTask<String> ft = new FutureTask<>(myCallable);
        new Thread(ft).start();
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程" + i);
        }
        //获取线程执行之后的结果
        try {
            //如果执行到这里,线程的结果还没计算完毕,会wait
            System.out.println(ft.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

线程的安全问题

多个线程同时操作一个数据,可能会造成数据修改异常,造成错误的结果。

线程同步

锁的范围越小,性能越好

  • 同步代码块

代码块上锁

image-20240311174635756

image-20240311175522387

  • 同步方法

方法上锁

image-20240311175806286

  • Lock锁

image-20240311180210085

	private final Lock lk = new ReentrantLock();

使用Lock一定要使用try/catch/finally,最后解锁,否则会造成死锁,确保早必要时释放锁。

线程通信(同步)

线程同步的前提一定是先要保证线程安全

image-20240311180924767

生产者与消费者

import java.util.ArrayList;
import java.util.List;
/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 18:11
 */
public class ThreadDemo {
    public static void main(String[] args) {
        Desk desk = new Desk();
        new Thread(()->{
            while (true) {
                desk.put();
            }
        },"厨师1").start();
        new Thread(()->{
            while (true) {
                desk.put();
            }
        },"厨师2").start();
        new Thread(()->{
            while (true) {
                desk.put();
            }
        },"厨师3").start();
        new Thread(()->{
            while (true) {
                desk.get();
            }
        },"吃货1").start();
        new Thread(()->{
            while (true) {
                desk.get();
            }
        },"吃货2").start();
    }
}

class Desk{
    private List<String> list = new ArrayList<>();
    //厨师123
    public synchronized void put(){
        try {
            final String name = Thread.currentThread().getName();
            if(list.isEmpty()){
                list.add(name + "做的肉包子");
                System.out.println(name + "做了一个肉包子");
                Thread.sleep(2000);
                this.wait();
                this.notifyAll();
            }else{
                this.wait();
                this.notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //消费者12
    public synchronized void get(){
        try {
            final String name = Thread.currentThread().getName();
            if (!list.isEmpty()){
                System.out.println(name + "吃了" + list.get(0));
                list.clear();
                Thread.sleep(2000);
                this.wait();
                this.notifyAll();
            }else{
                this.wait();
                this.notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程池

可复用的线程技术

image-20240311183732598

JDK5.0起提供了代表线程池的接口:ExecutorService

得到线程池的两种方式

  • 使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

临时线程什么时候创建?

新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。

线程池处理Runnable任务

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 22:11
 */
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "==> 输出");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

import java.util.concurrent.*;

/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 18:46
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {
        /*new ThreadPoolExecutor(   int corePoolSize,
                                    int maximumPoolSize,
                                    long keepAliveTime,
                                    TimeUnit unit,
                                    BlockingQueue<Runnable> workQueue,
                                    ThreadFactory threadFactory,
                                    RejectedExecutionHandler handler)*/

        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        Runnable target = new MyRunnable();
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
    }
}

线程池处理Callable任务

import java.util.concurrent.*;
/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 18:46
 */
public class ThreadPoolDemo {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        final Future<String> f1 = pool.submit(new MyCallable(100));
        final Future<String> f2 = pool.submit(new MyCallable(200));
        final Future<String> f3 = pool.submit(new MyCallable(300));
        final Future<String> f4 = pool.submit(new MyCallable(400));
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());
    }
}
  • 使用Executors(线程池工具类)调用方法返回不同特点的线程池对象
import java.util.concurrent.*;
/**
 * @author Pickle
 * @version V1.0
 * @date 2024/3/11 18:46
 */
public class ThreadPoolDemo {
    public static void main(String[] args) throws Exception {
        final ExecutorService ft = Executors.newFixedThreadPool(3);
        final Future<String> f1 = ft.submit(new MyCallable(100));
        final Future<String> f2 = ft.submit(new MyCallable(200));
        final Future<String> f3 = ft.submit(new MyCallable(300));
        final Future<String> f4 = ft.submit(new MyCallable(400));
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());
    }
}

大型并发系统中,如果使用Executors如果不注意可能会出现系统风险

线程状态

image-20240311225149723

悲观锁、乐观锁

悲观锁:一上来就加锁,每次只能一个线程进入访问完毕之后,再解锁。------线程安全,性能较差

image-20240311230545820

乐观锁:一开始不上锁,等要出现线程安全问题的时候才开始控制。------线程安全,性能好

image-20240311231110247

标签:Thread,System,线程,println,new,多线程,public
From: https://www.cnblogs.com/poteitoutou/p/18067349

相关文章

  • t01_多线程
    进程与线程进程:进程是程序的基本执行实体线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位在Java中,进程(Process)和线程(Thread)是两个并发执行的概念,用于实现多任务处理和并发执行。它们都是操作系统和编程语言级别的概念,用于管理和执......
  • Spring多线程事务处理
    一、背景本文主要介绍了spring多线程事务的解决方案,心急的小伙伴可以跳过上面的理论介绍分析部分直接看最终解决方案。在我们日常的业务活动中,经常会出现大规模的修改插入操作,比如在3.0的活动赛事创建,涉及到十几张表的插入(一张表可能插入一行或者多行数据),由于单线程模型的关系,......
  • Java多线程基础用法
    线程创建线程创建的三种方式:Thread(继承Thread类)自定义线程类继承Thread类重写run()方法。编写线程执行体创建线程对象,调用start()方法启动线程packagecom.lily.demo01;publicclassTestThreadextendsThread{@Overridepublicvoidrun(){for......
  • QT 多线程
     第一种:静态函数1voidprint()2{3for(inti=0;i<5;i++)4qInfo()<<"helloglobalprint";5}6classMainWindow:publicQWidget7{8Q_OBJECT9public:10MainWindow(QWidget*parent=nullptr):QWidget(parent)......
  • 深入浅出Java多线程(十):CAS
    引言大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第十篇内容:CAS。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!在多线程编程中,对共享资源的安全访问和同步控制是至关重要的。传统的锁机制,如synchronized关键字和ReentrantLock等,能够有效防止多个线程......
  • 多线程系列(十六) -常用并发原子类详解
    一、简介在Java的java.util.concurrent包中,除了提供底层锁、并发同步等工具类以外,还提供了一组原子操作类,大多以Atomic开头,他们位于java.util.concurrent.atomic包下。所谓原子类操作,顾名思义,就是这个操作要么全部执行成功,要么全部执行失败,是保证并发编程安全的重要一环。相......
  • Linux多线程-线程同步
    线程同步当多个线程同时对一个共享数据进行操作时,会导致数据竞争,下面例子展示了数据竞争的情况:1#include<pthread.h>2#include<stdio.h>3#include<stdlib.h>4#include<string.h>5#include<unistd.h>67staticintval=0;8void*threadEntry(void*......
  • Linux多线程
    线程的概念线程是指程序中的一条执行路径。在一个进程中,至少有一个线程,称为主线程,通过主线程可以派生出其他子线程。Linux系统内核只提供了轻量级进程(light-weight process)的支持,并未实现线程模型。Linux本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。进程是......
  • 分布式锁——JVM锁、MySQL锁解决多线程下并发争抢资源
    分布式锁——JVM锁、MySQL锁解决库存超卖问题引入库存扣案例需求背景电商项目中,用户购买商品后,会对商品的库存进行扣减。需求实现根据用户购买商品及商品数量,对商品的库存进行指定数量的扣减publicStringdeductStock(LonggoodsId,Integercount){//1.查询商品......
  • 多进程、多线程知识再整理
    #threading模块'''cpython全局解释器锁导致同时只能有一个线程执行python,利用多cpu执行cpu密集型任务使用多进程,密集io型可以使用多线程并发classthreading.Thread(group=None,target=None,name=None,args=(),kwargs={},*,daemon=NoneThread类代表一个在独立控制线......