线程实现四种方式

  1. 继承Thread类

  2. 实现Runnable接口,重写Run方法

  3. 实现Callable接口,重写Call方法,此方式有返回值

  4. 利用线程池创建

如何启动线程

第一种方式,直接new对象,调用对象的start()方法

第二种方式,new 一个实现了Runnable接口的类,将这个对象作为Thread的有参构造方法的参数传入,调用Thread对象的start()方法

第三种方式, new 一个实现了Callable的接口的类,将这个对象作为FutureTask有参构造的参数传入,再把这个FutureTask对象作为Thread的有参构造方法的参数传入,调用Thread对象的start()方法

线程的生命周期:

1.新建状态:使用new之后,线程就处于新建状态

2.就绪状态:当调用了start方法之后,线程就处于就绪状态状态

3.运行状态:如果就绪状态的线程获取到cpu资源,就会处于运行状态,此时线程最为复杂,可以变为就绪状态,阻塞状态,死亡状态

4.阻塞状态:当一个线程执行了sleep,wait等方法,就处于阻塞状态

5.死亡状态:一个运行完的线程或其他终止 条件时,该线程就处于死亡状态

锁的问题

当线程开始多了起来就称为多线程,多线程一旦出现,那就出现线程安全问题,那么锁就用来解决线程安全问题

锁按照宏观分类,分为乐观锁和悲观锁。

乐观锁:指的是当一个线程执行时,他认为别的线程必定不会去执行,也就是说别的线程必定不会影响他,但是,他在最后会确认数据是否被修改。

举例:CAS ,Atomic,数据库可以设置version防止二类丢失更新,es的version

悲观锁:指的是一个线程运行时,他认为别的线程必定会执行,所以他会把其加锁,不让别的线程执行。

举例:synchronized ReentrantLock

synchronized用法:

在相应的代码块上加synchronized(){

}

()里面的参数可以是对象,也可以是字节码,无论是什么,都必须满足只有一份的情况。

()通常是this,或者是当前类的字节码

public class SyTest implements Runnable{private int a = 100;@Overridepublic void run() {for (int i = 0; i < 100; i++) {synchronized (this) {if (a > 0) {System.out.println(Thread.currentThread().getName() + "打印一手" + a--);}}}}public static void main(String[] args) {SyTest syTest = new SyTest();new Thread(syTest).start();new Thread(syTest).start();new Thread(syTest).start();}
}

ReentrantLock用法:

实列化lock对象,(程序中只有一份)在会产生线程安全的代码前加上锁,在finally代码块中解除锁

public class LockTest implements Runnable{private int a = 100;private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {for (int i = 0; i < 100; i++) {try{lock.lock();if (a > 0) {System.out.println(Thread.currentThread().getName() + "打印一手" + a--);}}finally {if(lock.isLocked()){lock.unlock();}}}}public static void main(String[] args) {LockTest syTest = new LockTest();new Thread(syTest).start();new Thread(syTest).start();new Thread(syTest).start();}
}

atomic基于CAS乐观锁实现

public class AtomicTest implements Runnable{private AtomicInteger a = new AtomicInteger(100);@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (a.get()> 0) {System.out.println(Thread.currentThread().getName() + "打印一手" + a.getAndDecrement());}}}public static void main(String[] args) {AtomicTest syTest = new AtomicTest();new Thread(syTest).start();new Thread(syTest).start();new Thread(syTest).start();}
}

利用ThreadLocal实现线程安全

public class ThreadLocalTest{public static void main(String[] args) {ThreadLocal<String> threadLocal = new ThreadLocal<>();//主线程设置值threadLocal.set("main-value");new Thread(()->{System.out.println("thread线程获取:"+threadLocal.get());    //打印null,新开的线程是获取不到主线程设置的值的threadLocal.set("thread-value");System.out.println("thread线程获取:"+threadLocal.get());    //打印thread-value}).start();//主线程设置值System.out.println("main线程获取:"+threadLocal.get());  //打印 main-value}
}

线程池

*线程池执行流程 :* 核心线程 => 等待队列 => 非核心线程 => 拒绝策略

PS: 线程池7个参数的构造器非常重要[重要]

CorePoolSize: 核心线程数,不会被销毁

MaximumPoolSize : 最大线程数 (核心+非核心) ,非核心线程数用完之后达到空闲时间会被销毁

KeepAliveTime: 非核心线程的最大空闲时间,到了这个空闲时间没被使用,非核心线程销毁

Unit: 空闲时间单位

WorkQueue:是一个BlockingQueue阻塞队列,超过核心线程数的任务会进入队列排队

SynchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务;

LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;

ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小

ThreadFactory:使用ThreadFactory创建新线程。 推荐使用Executors.defaultThreadFactory

Handler: 拒绝策略,任务超过 最大线程数+队列排队数 ,多出来的任务该如何处理取决于Handler

AbortPolicy丢弃任务并抛出RejectedExecutionException异常;

DiscardPolicy丢弃任务,但是不抛出异常;

DiscardOldestPolicy丢弃队列最前面的任务,然后重新尝试执行任务;

CallerRunsPolicy由调用线程处理该任务

可以定义和使用其他种类的RejectedExecutionHandler类来定义拒绝策略。、

常见线程池有四种

CachedThreadPool:可缓存

FixedThreadPool :固定长度

SingleThreadPool:单个

ScheduledThreadPool:可调度

1.CachedThreadPool

这种线程池内部没有核心线程,线程的数量是有限制的 最大是Integer最大值。

在创建任务时,若有空闲的线程时则复用空闲的线程(缓存线程),若没有则新建线程。

没有工作的线程(闲置状态)在超过了60S还不做事,就会销毁。

适用:执行很多短期异步的小程序或者负载较轻的服务器。

public class cachedThread {public static void main(String[] args) {ExecutorService cachedThreadPool = Executors.newCachedThreadPool();for (int i = 0; i < 100; i++) {cachedThreadPool.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"执行");}});}}
}

FixedThreadPool :固定长度

该线程池的最大线程数等于核心线程数,所以在默认情况下,该线程池的线程不会因为闲置状态超时而被销毁。

如果当前线程数小于核心线程数,并且也有闲置线程的时候提交了任务,这时也不会去复用之前的闲置线程,会创建新的线程去执行任务(必须达到最大核心数才会复用线程)。如果当前执行任务数大于了核心线程数,大于的部分就会进入队列等待。等着有闲置的线程来执行这个任务。

适用:执行长期的任务,性能好很多

public class FixedThread {public static void main(String[] args) {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);for (int i = 0; i < 100; i++) {fixedThreadPool.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"执行");}});}}
}

SingleThreadPool:单个

有且仅有一个工作线程执行任务

所有任务按照指定顺序执行,即遵循队列的入队出队规则。

适用:一个任务一个任务执行的场景。 如同队列

public class singleThread {public static void main(String[] args) {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();for (int i = 0; i < 100; i++) {singleThreadExecutor.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"执行");}});}}
}

ScheduledThreadPool:可调度

DEFAULT_KEEPALIVE_MILLIS就是默认10L,这里就是10秒。这个线程池有点像是CachedThreadPool和FixedThreadPool 结合了一下。

不仅设置了核心线程数,最大线程数也是Integer.MAX_VALUE。

这个线程池是上述4个中唯一一个有延迟执行和周期执行任务的线程池。

适用:周期性执行任务的场景(定期的同步数据)

public class ScheduledThread {public static void main(String[] args) {//带缓存的线程,线程复用,没有核心线程,线程的最大值是 Integer.MAX_VALUEScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);//延迟 n 时间后,执行一次,延迟任务
//        executorService.schedule(new Runnable() {//            @Override
//            public void run() {//                System.out.println("延迟任务执行.....");
//            }
//        },10, TimeUnit.SECONDS);//定时任务,固定 N 时间执行一次 ,按照上一次任务的开始执行时间计算下一次任务开始时间
//        executorService.scheduleAtFixedRate(()->{//            System.out.println("定时任务 scheduleAtFixedRate 执行 time:"+System.currentTimeMillis());
//            try {//                Thread.sleep(1000);
//            } catch (InterruptedException e) {//                e.printStackTrace();
//            }
//        },1,1, TimeUnit.SECONDS);//定时任务,固定 N 时间执行一次 ,按照上一次任务的结束时间计算下一次任务开始时间executorService.scheduleWithFixedDelay(()->{System.out.println("定时任务 scheduleWithFixedDelay 执行 time:"+System.currentTimeMillis());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}},1,1,TimeUnit.SECONDS);}
}

java之线程相关juc相关推荐

  1. java与线程相关的一些重要方法1(不涉及并发包)-Object的wait(long timeout)和wait()

    一.Object的wait(long timeout)方法 javaAPI中关于wait(long timeout)放的说明是这样的: 导致当前线程等待,直到其他线程调用此对象的java.lang.O ...

  2. java和线程相关的关键字有哪些_Java中有哪些机制来保证线程安全?synchronized关键字和volatile关键字...

    想要解决线程安全问题,首先要知道为什么会造成线程不安全? 在单线程中,我们从来没有提到个线程安全问题,线程安全问题是只出现在多线程中的一个问题.因为多线程情况下有共享数据,每个线程都共享这些数据并对这 ...

  3. java线程实例题_java线程相关试题实例源码代码

    java线程相关试题实例源码代码. /** * 计算输出其他线程锁计算的数据 */ class ThreadA { public static void main(String[] args) { T ...

  4. Java线程相关的热门面试题

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成 ...

  5. java中线程总结,JAVA中线程的相关小结

    ·什么是线程 线程:进程中负责程序执行的执行单元.一个进程中至少有一个线程. 多线程:一个进程中包含有多个线程,但CPU在同一时间只允许一个线程的进行.所以有多个线程的运行是根据CPU切换完成,如何切 ...

  6. java 线程相关的属性介绍

    属性名称 用途 注意事项 id (线程id) 标识不同的线程 被后续创建的线程使用,唯一性,不能被修改 name (线程名称) 定位问题 开发和排查问题的时候用得到,定义名字要清晰有意义 isDaem ...

  7. java线程组 线程池_JAVA多线程(三)-----线程组、线程池和线程相关类

    一.线程组和未处理的异常 Thread类提供了如下几个构造器来设置新创建的线程属于哪个线程组: Thread(ThreadGroup group,Runnable target):以target的ru ...

  8. Java高频面试题(2022) - Java、Mysql、JUC、JVM、SSM

    目录 不好使!点右边小目录定位: 目录 JavaSE HashMap底层原理?★★ Vector.ArryList.LinkedList 的区别与联系 Hashtable与HashMap的区别?如何解 ...

  9. java多线程高级:JUC

    文章目录 java多线程高级:JUC 1 多线程锁 1.1 传统synchronized 1.2 Lock接口 1.3 Synchronized和Lock的区别 2生产者和消费者问题 2.1 Sync ...

最新文章

  1. Netflow/IPFIX 流量收集与分析
  2. Java学习|先定一个小目标比如让行为聚焦
  3. 计算机组成原理怎么考察的,计算机组成原理课程考察报告(论文).doc
  4. 【人物】养车点点费岸:给O2O产品经理的四点意见
  5. pde lec 3 part 1
  6. cookies可以跨域了~单点登陆(a.com.cn与b.com.cn可以共享cookies)
  7. ios 顶部tab滑动实现_iOS开发之多表视图滑动切换示例(仿头条客户端)
  8. 归纳一下:C#线程同步的几种方法
  9. Windows学习总结(14)——最常用的Windows快捷键再总结
  10. 操作系统定义、功能、特征、分类介绍
  11. C语言线性表学生管理系统,c语言 学生信息管理系统(线性表版)
  12. 1000套电子物联网专业毕业设计和电赛设计资料822份
  13. 年龄和血压对照表,有必要了解!
  14. R语言中dim函数_R语言入门:函数介绍(3)—— %gt;%
  15. ROS基础(三)——订阅者Subscriber编程实现
  16. 深入理解多线程(四)—— Moniter的实现原理
  17. ElasticSearch 23 种映射参数详解
  18. Android 面经:我是如何进入大厂腾讯的?
  19. 联想升级Win11后触摸板失灵怎么办?
  20. 怎么搭建自己的网站赚钱,个人网站怎么操作

热门文章

  1. Spring Framework--SpringMVC(1)--DispatcherServlet
  2. [Oracle] Data Pump 详细使用教程(5)- 命令交互模式
  3. SyncML协议简述
  4. 关于npm邮箱验证问题
  5. [ES6] 细化ES6之 -- 块级作用域
  6. HTML-列表、表格、表单
  7. 链表、头指针、头结点
  8. 机器学习实战8-sklearn降维(PCA/LLE)
  9. 7-45 银行业务队列简单模拟 (10 分)
  10. 7-138 打印沙漏 (20 分)