java基础之线程

线程笔记整理

线程Thread常用方法

一. 获取线程名称
1.void setName(String name) 将此线程的名称更改为等于参数name 
2.String getName() 返回此线程的名称
3.static Thread currentThread() 返回对当前正在执行的线程对象的引用
  • 获取垃圾回收机制所在线程的线程名
Finalizer
线程休眠
1.static void sleep(long millis)
是一个静态方法,而且方法上还有编译时异常的声明,使用时一定要处理异常. 使
当前正在执行的线程停留(暂停执行)指定的毫秒数, 1s = 1000ms, 过了指定的
时间还会醒,可以继续执行任务
线程优先级
1.final int getPriority() 返回此线程的优先级

 //更改此线程的优先级线程默认优先级是5 线程优先级的范围是:1-10
2.final void setPriority(int newPriority)
线程礼让
1.static void yield()
线程让步,暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程, 若
队列中没有同优先级的线程,忽略此方法; 当前线程让出CPU资源后,依然有获取
CPU的机会,并不是让步之后就不能获取到CPU资源了.
休眠中断
1.public void interrupt()  //中断这个线程状态,不是中断任务.
守护线程
1.public final void setDaemon(boolean on)
//将此线程标记为daemon线程或用户线程。当运行的唯一线程都
//是守护进程线程时,Java虚拟机将退出。

2.isDaemon() 判断一个线程是否为守护线程

1.判断垃圾回收机制所在线程是不是守护线程?

gc存在的作用,释放堆内存中没有引用指向的对象空间的.扩 大了堆内存的可用空间范围,不就为其他任务在申请对象空间提供良好环境了.作用讲gc所在线程就应该是守护线程. 

2.判断主线程是不是守护线程?

当自己没有开启任何线程的时候,发现main方法也能运行,而main方式实在主 线程中运行,如果主线程是守护线程,jvm就起不来.而现在main方法是可以运行的,所以主线程不可能是守护线程. 

二. 多线程安全问题

线程抢占 多线程并发问题 多个线程同时抢到同一个方法入口

如重复买票的问题

解决问题方法:保证线程执行任务的原子操作
保证一条线程在操作某个任务的时候,一定要保证他的操作都必须完全都结束,其他的线程才有机会做这个操作
同步代码块
synchronized(锁对象) { 
原子操作的代码;【有可能出现线程安全问题的代码】 
}

//举个栗子
   @Override
    public void run() {
            //票数不为0 就一直买票
            while (ticket > 0) {
                synchronized ("A") {
                    //"A"字符串常量存储在常量池中,只有一份
                        if (ticket >0) {
                            ticket = ticket - 1;
                            //获取线程对象
                            Thread t = Thread.currentThread();
                            System.out.println(t.getName() + "卖出了第" + (ticket + 1) + "张票,剩余" + ticket + "张票");
                     }
                }
        }
    }
  • 说明
1. 锁对象可以是任何引用类型的对象,只要是一个java对象就可以当做锁对象
2. 锁对象一旦被确定下来要保证唯一性, 锁对象只能有一份
  • 同步代码块执行原理
一段代码一旦使用同步代码块之后, 线程只要进入同步代码块,就要先获取锁对象,只有拿到锁对象才能进入同 步代码块执行任务, 在这个线程执行任务期间,CPU可能会把资源切换到其他线程,即使其他线程也要进入这个 同步代码块,因为锁对象已经被之前的线程拿走了,它没有锁对象,依然进不来, 只能等之前线程执行完,把锁 对象归还,其他线程才有机会拿到锁对象,执行里面任务.
  • 有点和缺点
好处:解决了多线程的数据安全问题 
弊端:当线程很多时,因为每个线程执行任务时都要先判断是否有锁对象对象可用,执行完之后把锁对象归还,这是很耗费资源的,无形中会降低程序的运行效率
同步方法
  • 格式
同步成员方法: 
修饰符 synchronized 返回值类型 方法名(方法参数) {
	方法体; 
}

//举个栗子

//成员同步方法 使用所对象默认就是this
    public synchronized void sell(){
        if (ticket > 0){
            ticket = ticket-1;
            System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket+1)+"张,剩余"+(99-ticket));
        }
    }


如果你发现你写的一个成员方法,这个方法内部所有的代码都使用同代码块给包裹了,并且使用的锁对象是 this的时候.就可以使用同步成员方法简化这个方法 
    
    修饰符 返回值类型 方法名(方法参数) { 
    synchronized(this) {
        法体; 
    } 
}

//举例
public void sell (){
        //this指外面new的st对象 多线程执行的是同一个对象
        synchronized (this){
            if (ticket > 0){
                ticket = ticket-1;
                System.out.println(Thread.currentThread().getName()+"卖出第"(ticket+1)+"张票,剩余"+(100-ticket));
            }
        }
    }:因为同步成员方法默认的锁对象就是:this
  • 同步静态方法
同步静态方法: 
修饰符 static synchronized 返回值类型 方法名(方法参数) { 
    方法体; 
}

什么时候使用同步静态方法? 如果你发现你写的一个静态方法,这个方法内部所有的代码都使用同步代码块给包裹了,并且使用的锁对 象是当前类类对象的时候(类名.class).就可以使用同步静态方法简化这个方法 
    
    修饰符 static 返回值类型 方法名(方法参数) { 
    synchronized(当前类类名.class) { 
        方法体;
    } 
}

因为同步静态方法默认的锁对象就是:当前类的类对象,类名.class
    
    //举例
//静态同步方法,默认使用锁对象就是当前的类对象SellTicket.class
    public static synchronized void sell(){
        if (ticket > 0){
            ticket = ticket-1;
            System.out.println("静态方法 "+Thread.currentThread().getName()+"卖出第"+(ticket+1)+"张,剩余"+(99-ticket));
        }
    }   



public static void sell() {
        synchronized (SellTicket.class){
            if (ticket > 0){
                ticket = ticket-1;
                System.out.println("静态方法 "+Thread.currentThread().getName()+"卖出第"+(ticket+1)+"张,剩余"+(99-ticket));
            }
        }
    }

Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁.
    
    ReentrantLock构造方法
        ReentrantLock() 创建一个ReentrantLock的实例
    
    
    加解锁方法
    void lock() 获得锁
	void unlock() 释放锁
  • 总结

无论使用哪种解决方案,原理都是要线程同步,加锁同步。

加锁原则:保证锁唯一

线程死锁的概述以及现象演示
  • 概述:

线程死锁是指由于两个或者多个线程互相持有对方所需要的锁资源,导致这些线程处于等待状态,无法继续执行. 实际工作不要写出死锁,要学会规避死锁.

三. 线程状态[线程的生命周期]

  • 概述

线程生命周期,线程对象从生到死一个过程. 当线程被创建并启动以后,它既不是一启动就进入了执行状态, 也不是一直处于执行状态。线程对象在不同的时期有不同的状态。

线程状态具体含义
NEW一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程象,没有线程特征。
RUNNABLE当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的度。也可以描述线程正在CPU中执行.
BLOCKED当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入BLOCKED状态;当该线程持有锁时,该线程将变成Runnable状态。
WAITING一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。
TIMED_WAITING一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。
TERMINATED一个完全运行完成的线程的状态。也称之为终止状态、结束状态
  • getState():获取线程当前的状态值

四线程池

线程池概述
  • 概述:一个装着多条线程对象的容器就是线程池.

  • 线程池存在的意义

1.系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理的时间. 
2.系统资源的消耗,这样就有点"舍本逐末"了。针对这一种情况,为了提高性能,我们就可以采用线程池。线程池在启动的时,会创建大量空闲线程(没有执行任务的线程),当我们向线程池提交任务的时,线程池就会找到一个空闲线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次放回到线程池中称为空闲状态。等待下一次任务的执行。这样就可以达到对线程对象重复利用的效果.
Executors获取线程池
  • 使用Executors中所提供的静态方法来创建线程池
	1.static ExecutorService newCachedThreadPool()  //创建一个默认的线程池 
   
     //创建一个指定最多线程数量的线程池 
    2.static ExecutorService newFixedThreadPool(int nThreads) 
        
     //创建只有一个线程对象的线程池
    3.static ExecutorService newSingleThreadExecutor() 
  • ExecutorService(这才是线程池的类型)
使用: 
    1、准备线程任务【Runnable Callable2、把线程任务提交给线程池【自动委派内部的线程对象来执行】 
    功能:
    submit(Runnable r):提交线程任务到线程池执行
    submit(Callable c):提交线程任务到线程池执行 
    shutdown():关闭线程池 如果任务已经提交但还没有执行,关闭池子之前,只要提交的任务都能执行
    shutdownNow():立即关闭线程池,如果任务提交还没有执行,关闭池子的时候,这些任务就不再执行了
线程池ThreadPoolExecutor()
  • 创建线程池对象 :
ThreadPoolExecutor t = new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间 ,存活时间单位,任务队列,创建线程工厂,任务的拒绝策略);

	corePoolSize: 核心线程的最大值,不能小于0 3 
    maximumPoolSize:最大线程数,不能小于等于0,maximumPoolSize >= corePoolSize 5 
    keepAliveTime: 非核心线程,空闲线程最大存活时间,不能小于0, 0表示不销毁 2 
    unit: 时间单位:TimeUnit.SECONDS 非核心空闲线程2秒后销毁 
    workQueue: 任务队列,不能为null ArrayBlockingQueue, 任务是先进先出. 		
    threadFactory: 创建线程工厂,不能为null Executors.defaultThreadFactory() 	   
    handler: 任务的拒绝策略,不能为null ThreadPoolExecutor提供的策略

keepAliveTime: 非核心线程,空闲线程最大存活时间,不能小于0, 0表示不销毁
unit: 时间单位:TimeUnit.SECONDS 非核心空闲线程2秒后销毁
workQueue: 任务队列,不能为null ArrayBlockingQueue, 任务是先进先出.
threadFactory: 创建线程工厂,不能为null Executors.defaultThreadFactory()
handler: 任务的拒绝策略,不能为null ThreadPoolExecutor提供的策略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值