当前位置: 首页 > news >正文

6、多线程

一、线程创建方法

1、继承Thread类
  1. 自定义线程类,继承(extends)Thread

  2. 重写run()方法

  3. 创建线程对象,调用start()方法启动线程

    MyThread thread1 = new MyThread();
    thread1.start();
    
2、实现Runnable类(常用,因为接口可以多继承)
  1. 自定义线程类RunnableTest,实现(implements)Runnable类

  2. 重写run()方法

  3. 创建线程对象p,new Thread(p,“线程名称”).start()方法启动线程(线程名称可省略,主要用于区分多个相同对象)

    RunnableTest p=new RunnableTest();	Thread thread = new Thread(p);	thread.start;
    
3、实现Callable类、通过FutureTask获取返回值
public class MyCallable2 implements Callable<String> {@Overridepublic String call() throws Exception {for (int i = 0; i < 10; i++) {System.out.println("子线程 ");}return "我爱中国";}
}public static void main(String[] args) throws ExecutionException, InterruptedException {//FutureTask的泛型是MyCallable2类中call()的返回值类型FutureTask<String> myCallable2FutureTask = new FutureTask<>(new MyCallable2());Thread thread = new Thread(myCallable2FutureTask);thread.start();System.out.println("获取线程返回值,会阻塞线程,导致程序不往后执行:" + myCallable2FutureTask.get());//当前,下面的for会等待子线程中代码执行完毕后才会开始执行,原因:被前一行myCallable2FutureTask.get()阻塞了for (int i = 0; i < 10; i++) {System.out.println(" main ");}}

二、常用方法

1、线程休眠:thread.sleep();2、线程礼让(停止当前线程,重新让CPU调度):thread.yield();3、线程插队(强制优先执行p这个线程):thread.join();4、线程状态获取:thread.getState();5、获取线程名称:thread.currentThread.getName();6、获取线程优先级(设置用set,1-10之间,先设置再启动,优先级是占比相对大,不是绝对优先):thread.getPriority();7、守护线程(默认位false,即用户线程,设为true时,是守护线程,守护其他线程结束便结束) :thread.setDaemon(true);8、同步监视器,隐式锁,synchronizedOjb{增删改方法}

三、线程的生命周期

  • 新建
  • 可运行
  • 被终止
  • 阻塞
  • 无限等待
  • 计时等待

四、锁

1、隐式锁:synchronized
public class Demo01 {public static void main(String[] args) {/*** 1、同步代码块* 格式:*      synchronized(同步锁对象){*          操作共享资源的代码*      }*      * 2、同步方法* 格式:*      修饰符 synchronized 返回值类型 方法名称(形参列表) {*              操作共享资源的代码*      }*/Runnable runnable = new Runnable() {int ticket = 100;@Overridepublic void run() {while (true){/*synchronized1、确保多个线程使用的是同一个锁对象即可,锁对象可以是任意对象。2、如果多个线程共用同一个runnable对象,runnable的run方法内可以使用this作为锁对象。3、对于静态方法建议使用字节码(类名.class)对象作为锁对象,其他方法也能使用字节码(类名.class)对象作为锁对象*///1、同步代码块synchronized (this){if(ticket>0){System.out.println(Thread.currentThread().getName()+" 卖出了第 "+ticket+" 张票");ticket--;}else {break;}}}}//2、同步方法private synchronized void tellticket(){if(ticket>0){System.out.println(Thread.currentThread().getName()+" 卖出了第 "+ticket+" 张票");ticket--;}}};Thread thread1 = new Thread(runnable, "窗口1");Thread thread2 = new Thread(runnable, "窗口2");Thread thread3 = new Thread(runnable, "窗口3");thread1.start();thread2.start();thread3.start();}
}
2、显式锁,ReentrantLock,手动开启关闭锁。
public class Demo03 {public static void main(String[] args) {/*** Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象*      void lock():获得锁*      void unlock():释放锁*/ReentrantLock lock = new ReentrantLock();Runnable runnable = new Runnable() {int ticket = 100;@Overridepublic void run() {while (true) {try {//获得锁lock.lock();if (ticket > 0) {System.out.println(Thread.currentThread().getName() + " 卖出了第 " + ticket + " 张票");ticket--;} else {break;}} finally {//释放锁lock.unlock();}}}};Thread thread1 = new Thread(runnable, "窗口1");Thread thread2 = new Thread(runnable, "窗口2");Thread thread3 = new Thread(runnable, "窗口3");thread1.start();thread2.start();thread3.start();}
}

五、线程池

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

    public static void main(String[] args) throws ExecutionException, InterruptedException {/*** ExecutorService的常用api:*      execute(Runnable runnable):执行任务/命令,没有返回值,一般用来执行 Runnable 任务*      Future<T> submit(Callable<T> task):执行任务,返回未来任务对象获取线程结果,一般拿来执行Callable任务*      shutdown():等任务执行完毕后关闭线程池*      shutdownNow():立刻关闭,停止正在执行的任务,并返回队列中未执行的任务*///线程池创建方式1ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,//核心线程数5,//最大线程数5,//临时线程保存时间TimeUnit.HOURS,//时间单位new LinkedBlockingQueue<>(10),//任务队列Executors.defaultThreadFactory(),//创建工厂new ThreadPoolExecutor.AbortPolicy()//拒绝策略);//poolExecutor.submit创建线程任务//当创建线程任务的数量>任务队列的数量+核心线程数时,才开始新增调用临时线程for (int i = 0; i < 14; i++) {Future<String> future = poolExecutor.submit(() -> {System.out.println(Thread.currentThread().getName() + "线程  执行了");return Thread.currentThread().getName() + " 返回了";});System.out.println("future.get() = " + future.get());}/*//poolExecutor.execute创建线程任务//当创建线程任务的数量>任务队列的数量+核心线程数时,才开始新增调用临时线程for (int i = 0; i < 14; i++) {poolExecutor.execute(() -> System.out.println(Thread.currentThread().getName()+"线程执行了"));}*//*//线程池立刻关闭,停止正在执行的任务,返回未执行队列中List<Runnable> runnables = poolExecutor.shutdownNow();runnables.forEach(runnable -> System.out.println("runnable = " + runnable));*///线程池关闭poolExecutor.shutdown();}
    
  2. 使用Executors(线程池的工具类),调用方法返回不同特点的线程池对象
    public static void main(String[] args) {/*** newCachedThreadPool():*      线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉* newFixedThreadPool(int nThreads):*      创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它* newSingleThreadExecutor():*      创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程* newScheduledThreadPool(int corePoolSize):*      创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务*/ExecutorService executorService = Executors.newCachedThreadPool();}
    
2、线程池工作原理
  1. 当有新的任务交给线程池时,先由核心线程来处理。
  2. 当核心线程都在处理任务时,多的任务将存放到任务队列(LinkedBlockQueue)中。
  3. 当任务队列满了,核心线程都在处理任务,且处理任务的线程总数还没有达到最大线程数,线程工厂开始创建临时线程处理任务。
  4. 当核心线程和临时线程都在处理任务,且线程总数达到了最大线程数,,任务队列也满了,还有新的任务进来的就会开始拒绝策略。

六、其他

1、管程法,生产者/消费者模式,消费者不直接拿生产者的数据,而是从缓冲区拿数据
public static void main(String[] args) {//管程法Buffer buffer=new Buffer();new Thread(new Producer(buffer)).start();new Thread(new Consumer(buffer)).start();}//生产者static class Producer implements Runnable{Buffer buffer;public Producer(Buffer buffer) {this.buffer = buffer;}@Overridepublic void run() {for (int i = 1; i < 100; i++) {System.out.println("生产了第"+i+"个产品");buffer.add(new Product());}}}//消费者static class Consumer implements Runnable{Buffer buffer;public Consumer(Buffer buffer) {this.buffer = buffer;}@Overridepublic void run() {for (int i = 1; i < 100; i++) {System.out.println("  消费者消费了   第"+i+"个产品");buffer.reduce();}}}//产品static class Product{int id;}//缓冲区static class Buffer {Product[]products=new Product[10];int count =0;//生产这进行新增public synchronized void add(Product product){if(count==products.length){//缓冲区满了,等待减少try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}products[count]=product;count++;System.out.println("      缓存区有"+count+"个产品");this.notifyAll();}//消费者进行减少public synchronized void reduce(){if(count==0){//缓冲区空了,等待新增try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}count--;System.out.println("      缓存区有"+count+"个产品");this.notifyAll();}}
2、信号灯法,生产者/消费者模式,根据一个变量去确定是等待,还是执行
public class ThreadTest3 {public static void main(String[] args) {TV tv=new TV();new Thread(new Seeer(tv)).start();}}
//表演者
class Player implements Runnable{private TV tv;private String project;public Player(TV tv,String project) {this.tv = tv;this.project = project;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {tv.play(project);if(i%2==0){tv.play("吉祥如意的一家");}else{tv.play(project);}}}
}
//观看者
class Seeer implements Runnable{private TV tv;public Seeer(TV tv) {this.tv = tv;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {tv.see();}}
}class TV {private String project;private boolean flag=true;synchronized void play(String project){if(flag==true){System.out.println("表演者表演了<"+project+">");//Thread.currentThread().notifyAll();//这里只能用this,用这个会报错this.flag=false;this.project=project;this.notifyAll();}else {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}}synchronized void see(){if(flag==false){System.out.println("    观看者看了  "+project);this.flag=true;this.notifyAll();}else {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}}
}

http://www.mrgr.cn/news/25458.html

相关文章:

  • Android Studio报错: Could not find pub.devrel:easypermissions:0.3.0, 改用linux编译
  • 机器CPU突然升高的原因是什么?
  • [数据集][目标检测]脊椎检测数据集VOC+YOLO格式1137张1类别
  • 计算机网络 ---- OSI参考模型TCP/IP模型
  • rtems 5.3 qemu realview_pbx_a9 环境搭建:生成 rtems arm 工具链
  • 9月12号作业
  • Day23_0.1基础学习MATLAB学习小技巧总结(23)——句柄图形
  • Java教程:SE进阶【十万字详解】(上)
  • c语言--力扣简单题目(最后一个单词的长度)讲解
  • 人工智能如何改变我们的工作方式
  • 2024软件测试自动化面试题(含答案)
  • 每日OJ_牛客_马戏团(模拟最长上升子序列)
  • 9.12日常记录
  • 文心智能体应用:美国旅游助手的诞生
  • 小米路由器 BE7000 Docker、固件实践心得
  • 反编译app
  • 【hot100】力扣hot100部分题解
  • 测评造假?Mistral首个多模态模型Pixtral 12B发布
  • 基于SpringBoot的点餐平台网站
  • 如何在Word中复制整页内容并保持原有格式不变?