首页 > 编程语言 >Java笔记day10

Java笔记day10

时间:2024-07-25 20:30:15浏览次数:10  
标签:Java Thread 笔记 run 线程 new println day10 public

一,不同方式创建多个线程并打印

(1)定义了一个RunA实现Runnable接口,定义list存储数据,并重写了run方法 ,在run方法里定义循环向list中添加数据a;在main方法中创建a,b两个线程并引用该run方法,输出run对象的list和长度

 public static void mainB(String[] args) {
        RunA run=new RunA();
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(run.list);
        System.out.println(run.list.size());
    }
}
class RunA implements Runnable{
    public List list=new ArrayList();
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            list.add("a");
        }
    }
}

 

(2) 创建一个ThreadA类继承Thread(线程)定义一个list来存储数据,重写run方法,在main方法中创建ThreadA的对象线程a,b,并启动线程

class ThreadA extends Thread{
    public List list=new ArrayList();
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            list.add("a");
        }
    }
}
 //2.
    public static void mainB(String[] args) {
        RunA run=new RunA();
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(run.list);
        System.out.println(run.list.size());
    }
}

二,锁对象  Lock

注意:用Lock需要加锁解锁

创建锁对象

Lock lock=new ReentrantLock();//创建锁对象
//Lock lock=new ReentrantLock(true);//加true  设置为公平锁

加锁   成功返回true   失败返回false

lock.lock();

 解锁

lock.unlock();

 创建method方法,在主方法中调用,创建a,b线程并运行

package com.easy725;

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

public class EasyThreadB {

    //锁对象  Lock
    //用lock需要加锁解锁
    Lock lock=new ReentrantLock();//创建锁对象
    //Lock lock=new ReentrantLock(true);//加true  设置为公平锁
    //锁默认非公平锁
    public void method(){
//        lock.lock();//加锁
        //lock.tryLock()//尝试加锁   加锁成功true   失败返回false
        if(lock.tryLock()){//尝试加锁

        System.out.println(Thread.currentThread().getName()+"进入方法");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束方法");
        lock.unlock();//解锁
        }else{
            System.out.println("未成功加锁======去执行其它代码");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            method();
        }
    }

    public static void main(String[] args) {
        Runnable run=new EasyThreadB()::method;//当调用runnable里面的run方法时,相当于调用method方法·
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
    }
}

在运行过程中一次只能给加一个锁,下一个使用需要等待该锁解锁才能使用。进程0加锁成功先进入方法,执行进程;同时进程1请求加锁, 进入等待状态;直到进程0结束,同时还没有解锁,所以还会发生一次未成功加锁,然后发生解锁,进程1加锁成功进入方法

 

 三,读锁和写锁

进程进入方法后,写锁可以多个同时访问,读锁只能一个访问结束后才能开始下一个,读锁和写锁不能同时访问,只能写锁或读锁结束才能开始读锁或写锁。

main线程的任务是启动这些线程

cpu分配资源时是随机的,main线程在启动完别的线程以后它的结束也是随机的

所有锁都默认为非公平锁,只有ReentranLock可以设置为公平锁

package com.easy725;

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

public class EasyThreadC {
    public static ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
    public static ReentrantLock rl=new ReentrantLock();

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock= rrwl.readLock();//读锁
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功---读锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"方法结束");
        lock.unlock();
    }

    public static void methodWrite(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock= rrwl.writeLock();//写锁
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功---写锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"方法结束");
        lock.unlock();
    }


    public static void main(String[] args) {
        Runnable run=EasyThreadC::method;
        Runnable runWrite=EasyThreadC::methodWrite;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
        Thread e=new Thread(run);
        e.start();

        Thread f=new Thread(runWrite);
        f.start();
        Thread g=new Thread(runWrite);
        g.start();
        Thread h=new Thread(runWrite);
        h.start();
        Thread i=new Thread(runWrite);
        i.start();
        System.out.println("main线程结束----");
    }
}

 四,wait  和  notify  (等待和唤醒)

wait()方法可以使线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)

OBJ.wait();//让执行到该行代码的线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)

锁对象:synchronized关键字或显示锁ReentrantLock

例:

synchronized (OBJ){}//这里OBJ就是锁对象

notify()唤醒一条被该锁对象wait的线程   非公平锁

notifyAll();唤醒全部被锁对象wait的线程

synchronized (OBJ){
    OBJ.notify();//唤醒一条被该锁对象wait的线程   非公平锁
    OBJ.notifyAll();//唤醒全部被锁对象wait的线程     

wait和sleep的区别

(1)wait使Object中定义的方法 ,可以有锁对象,让执行到改行代码的线程进入到等待状态

sleep使Thread类中定义的静态方法,可以让执行到改行的线程进入等待状态

(2)区别:1.sleep需要传入一个毫秒,到达时间会自动唤醒

wait不能自动唤醒,必须要调用notify或notifyAll方法唤醒

2.sleep方法保持锁状态进入等待状态   

wait方法会解除锁状态,其他线程可以进入运行

package com.easy725;

public class EasyThreadD {
    public static final Object OBJ=new Object();//常量全部大写

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");

        synchronized (OBJ){
            OBJ.notify();//唤醒一条被该锁对象wait的线程   非公平锁
//            OBJ.notifyAll();//唤醒全部被锁对象wait的线程
            System.out.println(Thread.currentThread().getName()+"进入同步代码块");
            try {
                try {
                    System.out.println(Thread.currentThread().getName()+"进入等待状态");
                    OBJ.wait();//让执行到该行代码的线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)
                    System.out.println(Thread.currentThread().getName()+"重新运行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"结束同步代码块");
            OBJ.notify();//必须在同步代码块中才能唤醒
        }
    }

    public static void main(String[] args) {
        Runnable run=EasyThreadD::method;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
    }

}

五,线程池   池==重用

功能:完成线程的创建和管理,销毁线程

(1)使用ThreadPoolExecutor创建一个线程池tpe

BlockingQueue qu=new ArrayBlockingQueue(12);
ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,10,10,
        TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

(2)线程任务   Runnable   Callable

Runnable通过execute方法提交到线程池执行

Callable通过submit犯法提交到线程池执行,并返回一个futur对象,用来获取任务结果,使用Future.get()方法获取结果,这样可以阻塞主线程直到仍无执行完成

创建一个工作队列qu用来存放待执行的任务,( 创建Runnable任务run并提交到线程池执行)创建callable任务call到线程池执行,并获取future对象

注意:线程池对象需要关闭,使用shutdouwn()销毁线程

package com.easy725;

import java.util.Queue;
import java.util.concurrent.*;

public class EasyExecuters {
    //线程池   池==重用
    //完成线程创建和管理,销毁线程
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        BlockingQueue qu=new ArrayBlockingQueue(12);
        ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,10,10,
                TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

        //线程任务  Runnable   Callable
        Runnable run=EasyExecuters::method;
        tpe.execute(run);

        Callable<String> call=EasyExecuters::methodCall;
        Future<String> f=tpe.submit(call);
//        tpe.submit(run);

        System.out.println(f.get());//会等待线程执行完毕

        //线程池对象需要关闭
        tpe.shutdown();//销毁线程,关闭
    }
    public static void method(){
        System.out.println(Thread.currentThread().getName()+"执行代码");
    }
    public static String methodCall() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"执行代码call");
        Thread.sleep(2000);
        return "callResult";
    }
}

 六  线程池

1,线程池的七个参数

BlockingQueue queue=new ArrayBlockingQueue(12);
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
        5,8,10,
        TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()
);//(核心线程数,最大线程数,空闲线程存活时间,空闲线程存活时间单位,工作队列,线程工厂,拒绝策略)

2.四中回绝策略

AbortPolicy 放弃该任务并会抛出一个异常.RejectedExecutionException

CallerRunsPolicy 调用者执行,让传递任务的线程执行此任务

DiscardOldestPolicy 放弃队列中时间最长的任务,不会抛出异常

DiscardPolicy 直接放弃新的任务,不会抛出异常

3.线程池的工作原理

任务放置在工作队列中

1)池中是否有空闲的线程,如果有让该线程执行任务

2)如果池中有空闲的 线程,判断池中的线程数量没有达到核心线程数

3)如果没有达到核心线程数,创建新的线程执行任务,直到填满核心线程数,如果已经达到, 优先在队列中存储线程,直到队列填满

4)工作队列填满后再添加新的任务,判断是否达到最大线程数,如果没有就创建新的线程执行任务 ,直到创建到最大线程数

5)已经填满最大线程数,队列也已经填满,没有空闲的线程吗,就执行回绝策略 ;线程池中的线程达到(超过)核心线程数,超出的数量会根据存活时间进行销毁,直到数量达到核心线程数 。如果线程的数量少于核心线程数,不会消亡

4.java中内置的线程池对象

1)Executors.newCachedThreadPool();可以根据工作任务来创建线程,如果没有空闲的线程就创建新的线程,线程存活时间使60s

2)Executors.newFixedThreadPool(10);设定最大线程数量

3)Executors.newScheduledThreadPool(10);提供定时运行的处理方案

4)Executors.newSingleThreadExecutor();创建一个具有单个线程的线程池,保障任务队列完全按照顺序执行

理论上可以无线创建线程数

ExecutorService threadPoolExecutor=Executors.newCachedThreadPool();

package com.easy725;

import java.util.concurrent.*;

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

    BlockingQueue queue=new ArrayBlockingQueue(12);
    ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
            5,8,10,
            TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()
    );
//    ExecutorService threadPoolExecutor=Executors.newCachedThreadPool();//理论上线程数是无限创建的
    Runnable run=()->{
        System.out.println(Thread.currentThread().getName()+"执行代码");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"执行完毕");
    };
    for(int i=0;i<17;i++){
        threadPoolExecutor.execute(run);
    }
    threadPoolExecutor.shutdown();
    }
}

 

执行线程为17个,核心线程数刚好满五个

标签:Java,Thread,笔记,run,线程,new,println,day10,public
From: https://blog.csdn.net/qq_63095129/article/details/140688521

相关文章

  • 基于javaweb+mysql数据库实现的宠物领养|流浪猫狗网站
    《基于javaweb+mysql数据库实现的宠物领养网站》该项目含有源码、文档等资料、配套开发软件、软件安装教程、项目发布教程等使用技术:前端使用技术:JSP,HTML5,CSS3、JavaScript等后台使用技术:Servlet、Jdbc等数据库:Mysql数据库项目功能介绍:本系统为基于jsp+mysql的宠物领养......
  • 前段学习笔记
    <form>表单一般包含按钮<input>标签使用:登录,注册,搜索typetest文本,password密码,rodio单选,checkbox多选,file文件上传表格<table用来展示数据>table代表盒子,tr是行,th是表头单元格,td是内容单元格table无边框,加border属性添加边框。th有加粗和居中的效果普通在td里面......
  • [Java面向对象]接口
    接口接口中方法抛出异常在Java中,如果接口中的方法声明了抛出异常,那么实现这个接口的类必须处理这些异常。处理方式有两种:要么在实现方法中继续抛出异常,要么捕获并处理异常。假设接口定义如下:publicinterfaceMyInterface{voidmyMethod()throwsIOException;}继......
  • Java SE核心技术——2 Java基础语法
    一、关键字和保留字1.关键字关键字的定义和特点定义:被[java语言]赋予了特殊含义,用作专门用途的字符串。特点:关键字中所有字母都为小写。关键字不能用作变量名,方法名,类名,包名和参数。2.保留字定义:现在java尚未使用,但以后版本可能会作为关键字使用。自己使用时应避免使用。-......
  • JavaSE核心技术——3 流程控制语句结构
    一、顺序结构程序由上向下运行。二、分支结构1.if语句三种格式:2.switch-case注意:1.switch(表达式)中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举(jdk5.0),String(jdk7.0);2.break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺......
  • java的跨平台原理
    java的跨平台原理:Java跨平台的原理主要是通过Java虚拟机(JVM)来实现的。为啥需要跨平台:不同平台的机器码是不兼容的。在编译原理中,我们知道编译器将源代码翻译成特定平台的机器码,这样程序就可以在特定平台上运行。然而,不同平台的机器码是不兼容的,这就导致了跨平台的困难。......
  • 深度学习与图像识别学习笔记day1
    文件不可以与现有的包重名哦1、Theano(旧)一个python库,可用于定义、优化与计算数学表达式,特别是多维数组(numpy.ndarray),可以理解为一个数学表达式的编译器:用符号式语言定义程序员所需的结果,并可以高效的运行与GPU与CPU上。2、Tensorflow(新)基于计算图实现自动微分系统,tensorflow......
  • Java基础语法
    变量一、定义变量就是在程序运行过程中其值会发生改变的量。变量就是一个可以存储数据的容器。在Java语言中,所有的变量在使用前必须声明。变量存储在内存中开辟的存储空间中,根据数据类型的不同,存储空间的大小也会有所不同。变量的使用......
  • Java SE 核心技术——java初识
    一、JDK、JRE和JVM1.JDK、JRE和JVM定义JDK​即Java开发工具包。JDK是用于Java开发的一套工具包,里面包含了Java的编译器javac、Java程序打包工具jar、Java程序运行环境JRE、文档生成工具javadoc以及很多用于开发的工具。JRE​JRE是运行Java程序所需的环境,包括JVM......
  • java中的涉及到的cmd命令
    Java中的常见CMD命令在Java中,可以使用以下一些常见的命令行(cmd)命令:java:用于运行Java程序的命令。javac:用于编译Java源代码文件的命令。java-jar:用于创建和管理Java归档文件(JAR文件)的命令javap:用于翻译java字节码文件,可以看到class文件的内部结构不常用的命令:javadoc:用......