首页 > 编程语言 >java多线程(一)

java多线程(一)

时间:2022-11-24 15:06:37浏览次数:42  
标签:java System 线程 println new 多线程 public out


初始化线程的四种方式

1、继承Thread

public static void main(String[] args) {
System.out.println("main .... statt");
new Thread01().start();
System.out.println("main ... end");
}
public static class Thread01 extends Thread{
@Override
public void run() {
System.out.println("当前线程:"+Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:"+ i);
}
}

运行结果 

java多线程(一)_阻塞队列

 

2、实现Runnable接口

public static class Runable01 implements Runnable{
@Override
public void run() {
System.out.println("当前线程:"+Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:"+ i);
}
}

 

public static void main(String[] args) {
System.out.println("main .... statt");
//new Thread01().start();
Runable01 runable01 = new Runable01();
new Thread(runable01).start();
System.out.println("main ... end");
}

java多线程(一)_多线程_02

 

3、实现Callable+futureTask

该方法是可以获取线程执行结果的。

public static class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("当前线程:"+Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:"+ i);
return i;
}
}
public static void main(String[] args) {
System.out.println("main .... start");
//new Thread01().start();

//Runable01 runable01 = new Runable01();
//new Thread(runable01).start();

Callable01 callable01 = new Callable01();
FutureTask<Integer> task = new FutureTask<Integer>(callable01);
new Thread(task).start();

System.out.println("main ... end");
}

java多线程(一)_并发_03

 但是,使用Callable是可以获取线程的返回结果的。

public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main .... start");
//new Thread01().start();

//Runable01 runable01 = new Runable01();
//new Thread(runable01).start();

Callable01 callable01 = new Callable01();
FutureTask<Integer> task = new FutureTask<Integer>(callable01);
new Thread(task).start();
Integer integer = task.get();
System.out.println("返回结果为===="+integer);

System.out.println("main ... end");
}

执行结果:

java多线程(一)_java_04

 虽然有了异步线程,但是代码还是从上往下执行,原因就是线程调用了fuutetask的get方法是阻塞式等待。

4、线程池

为什么要用线程池?

如果我们后来的业务逻辑非常多,都写我们的原生代码,new Thread().start();问题是非常大的。这就代表我们公司有新任务,就招聘一名员工。任务多了之后,最终会将资源(内存,堆,栈)耗尽。

我们以后在业务代码里边,以上三种启动线程的方式我们都不用。应该将所有的多线程异步任务,都交给线程池来执行处理。(公司就50个员工,以后什么活就分配给这50个员工中的某一个,当然如果这个人有活,就等他处理完了,再处理新任务。达到了资源控制。)

1、降低资源的消耗

通过重复利用已经创建好的线程降低线程创建和销毁带来的损耗;

2、提高响应速度

因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配的状态,当任务来的时候,无需创建新的线程就能执行,节省了线程创建的时间。

3、提高线程的可管理性

线程池会根据当前系统特点,对池内的线程进行优化处理,减少创建和销毁带来的系统开销。无限的创建和销毁不仅消耗系统资源,还降低系统的稳定性。

JUC里边有个最快的方式得到线程池,

ExecutorService pool = Executors.newFixedThreadPool(10);

当然,这个线程池应该是整个系统一个线程池,而不是每次都创建一个线程池。

线程池执行的方法调用如下:

java多线程(一)_并发_05

//        pool.submit(new Runable01());
pool.execute(new Runable01());

 

区别如下:

execute的方法类型是void。submit有返回结果。

返回结果:

java多线程(一)_多线程_06

线程池的创建方式

1、Executors类

2、原生线程池

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();
//JDK源码
public ThreadPoolExecutor(int corePoolSize, //核心线程数[一直存在,除非设置了核心线程超时销毁的属性-allowCoreThreadTimeOut]:线程池创建好以后,就准备就绪的线程数量,等待接收异步任务去执行。只是new了几个Thread,但是并没有start();
int maximumPoolSize, //线程池的最大线程数量,控制资源并发。
long keepAliveTime, //存活时间:当我们线程数量大于核心线程数量的时候,只有线程空闲大于指定的最大存活时间,非核心线程释放。
TimeUnit unit,
BlockingQueue<Runnable> workQueue,//阻塞队列,如果任务有很多,把(总的异步任务数量-最大线程数量),放入到队列里边。只要线程空闲了,就去队列里边取出新的任务,继续执行。
ThreadFactory threadFactory,//创建线程的工厂,默认的。
RejectedExecutionHandler handler) { //如果队列满了,按照指定的拒绝策略,拒绝执行我们的任务。
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

 

线程池的工作顺序

1、线程池创建好,准备好core数量的核心线程,准备接受任务。

2、 新的任务进来,用core准备好空闲线程执行。

(1)core满了,就将新进来的线程放入到阻塞队列中去,空闲的core就会自己去阻塞队列获取任务执行。

(2)阻塞队列满了,就直接开新线程执行,最大只能开到max的执行数量。

(3)max都执行好了,max-core数量空闲的线程会在keepAliveTime指定的时间后,自动销毁,最终保持到core大小。

(4)如果线程开到了max的数量,还有新任务进来,就会使用reject指定的拒绝策略进行处理。

1、可以丢弃

2、可以同步执行。new thread().start()是异步的。

java多线程(一)_并发_07

 

AbortPolicy:抛弃策略;抛出异常;

DiscartPolicy:抛弃策略,不抛出异常;

java多线程(一)_并发_08

 

CallerRunsPlicy:的run()是同步执行的,只有new Thread().start()才是异步执行的。

3、所有的线程都是由指定的factory创建的。

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10000),//不指定的话,默认是Integer的最大值。一直占用内存。
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()//丢弃策略
);

 

线程池的种类

Executors.newCachedThreadPool();//核心线程数量是0个,但是最大线程数很大,60秒不用就回收
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
Executors.newFixedThreadPool();//最大线程数=核心线程数,核心线程从阻塞队列中取任务。阻塞队列满了不会创建非核心线程。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
Executors.newScheduledThreadPool(); //可以存放定时延期执行的任务线程
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
Executors.newSingleThreadExecutor() //核心线程=最大线程=1,线程执行完毕一个,就从阻塞队列中获取一个任务。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}

总结

由此可见,方式1和方式2,都是异步的,主线程是无法获取到其他线程的结果的。

FutureTask不仅可以接收callable参数,Runable参数也是可以接收的。

JDK源码如下:

public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}

public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}

runable方法配合futureTask实现返回值也是可以的,把返回值配置到result对象里边即可。

标签:java,System,线程,println,new,多线程,public,out
From: https://blog.51cto.com/u_15890333/5883990

相关文章

  • 使用selenium定时爬取网页内容-java版本
    使用场景某些网页有反扒机制,使用jsoup和httpclient不能满足要求,使用selenium可以。环境配置​​https://registry.npmmirror.com/binary.html?path=chromedriver/​​下载解......
  • java LinkedList , ArrayDeque, ArrayList区别
    linkedlist  既实现了 list接口,又实现了 queue,deque接口, 底层用链表数据结构,便于增删元素和顺序迭代arraydeque 实现了 queue和deque接口,底层用数组实......
  • 新建java项目及案例 练习
    1.打开IDEA软件2.在工具栏中点击File,下拉框中找到New-》Project  3.点击Maven-》NEXT 4.显示以下界面,修改名称,点击Finish完成 5.显示以下界面,选择pom.xml文......
  • java proguard混淆通配符
    类名通配符如下:|通配符|含义||---||?|匹配单个字符,包名分隔符(.)除外||*|匹配除(.)外的任意字符||**|匹配任意字符(包含.),如com.rush.**匹配com.rush包下......
  • 【Java Servlet 开发系列之一】在mac系统安装Apache Tomcat的详细步骤
    本站文章均为​​ 李华明Himi ​​​原创,转载务必在明显处注明:对于ApacheTomcat估计很多童鞋都会,那么今天就简单说下在mac上进行tomcat的安装;  第一步:下载Tomcat ......
  • java 基础——数组
    什么是数组?官方定义:数组(Array)是有序的元素序列。  简单来说:可以把数组想象成一个线性数据结构,用来装东西的,每个东西有自己的编号,并且编号是从0开始(重点) 直接来看......
  • 匆匆那年之Java程序员之最近两周的面试总结:
    匆匆那年之Java程序员之最近两周的面试总结:(一):匆匆那年之来帝都之初:还记得那是2011年的冬天,我们一行20多个同学一起来到了这个一直向往的城市首都,刚到北京是凌晨4点30,......
  • JAVA IO 快速入门
      packagecom.example.demo;importjava.io.File;importjava.io.IOException;publicclasstest{publicstaticvoidmain(String[]args)throwsIOExcep......
  • Java-Jdbc,JDBC连接Oracle11g实例:
    很长时间没用Oracle数据库了,今天在公司的电脑上装了一个Oracle11g,安装完成后,顺便写了个简单的Jdbc连接Oracle的例子,现在记录一下,方便以后查看:例子很简单,直接上代码:(注意:在测......
  • kotlin类似javalist map所谓c shape 或ios那边的字典的遍历循环和创建以及泛型
    println("testlengthfunc:${getObjectLength("Howlongdoihave,please?")}");//geLength会出现会重写的情况,应该是自动倒入了某些系统的类导致的。varlist=li......