线程:
多核:多个cpu 一个cpu一个时间节点只能处理一个线程
程序:软件,工程
进程:正在运行的程序(至少有一个线程)
线程:进程中的任务单位
并发:指两个或多个事件在同⼀个时间段内发⽣。
并⾏:指两个或多个事件在同⼀时刻发⽣(同时发⽣)。
主方法就是一个线程 主线程 main 在 main() 调⽤时候被创建
创建线程的方法
方式一: 只能继承一个类, 功能性单一
1.自定义类, 继承Thread
2.重写run方法
3.在主程序中创建线程对象
4.开启线程 start()
Thread的构造:
public Thread() :分配⼀个新的线程对象。
public Thread(String name) :分配⼀个指定名字的新的线程对象。
public Thread(Runnable target) :分配⼀个带有指定⽬标新的线程对象。
public Thread(Runnable target, String name) :分配⼀个带有指定⽬标新的线程对象并指定名字。
方式二: 实现接口
1.自定义类, 实现Runnable接口
2.实现run方法
3.创建线程对象 使用Runnable对象来构造
4.开启线程 start
方式三: 匿名内部类
Thread 和 Runnable 的区别
如果⼀个类继承 Thread,则不适合资源共享。但是如果实现了 Runable 接⼝的话,则很容易的实现资源共享。
总结:实现 Runnable 接⼝⽐继承 Thread 类所具有的优势:
1. 适合多个相同的程序代码的线程去共享同⼀个资源。
2. 可以避免 java 中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独⽴。
4. 线程池只能放⼊实现 Runable 或 Callable 类线程,不能直接放⼊继承 Thread 的类。
Run方法任何时刻都有可能被打断
优先级只是提升了这个线程的执行概率
GC -> 垃圾回收机制
setDaemon(true):如果 true ,将此线程标记为守护线程。设置守护线程,所有的”前置”线程都结束了,守护线程也结束(当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。)
线程通信 sleep()等待 带着锁 wait()等待会释放锁(别的等待会释放锁)
join(long millis)等待最多millis毫秒(系统过去millis毫秒)后无论之前线程有没有结束,都开始
线程同步:
1. 同步代码块:synchronized 关键字可以⽤于⽅法中的某个区块中,表示只对这个区块的资源实⾏互斥访问
2. 同步⽅法:使⽤ synchronized 修饰的⽅法,就叫做同步⽅法,保证A线程执⾏该⽅法的时候,其他线程只能在⽅法外等着。
3. 锁机制:java.util.concurrent.locks.Lock 机制提供了⽐synchronized代码块和synchronized⽅法更⼴泛的锁定操作,同步代码块/同步⽅法具有的功能Lock都有,除此之外更强⼤,更体现⾯向对象。
Lock锁也称同步锁,加锁与释放锁⽅法化了,如下:
public void lock() :加同步锁。 public void unlock() :释放同步锁。
线程通信: 等待唤醒机制 wait/notify 就是线程间的⼀种协作机制。
调⽤wait和notify⽅法需要注意的细节:
1. wait⽅法与notify⽅法必须要由同⼀个锁对象调⽤。因为:对应的锁对象可以通过notify唤醒使⽤同⼀个锁对象调⽤的wait⽅法后的线程。
2. wait⽅法与notify⽅法是属于Object类的⽅法的。因为:锁对象可以是任意对象,⽽任意对象的所属类都是继承了Object类的。
3. wait⽅法与notify⽅法必须要在同步代码块或者是同步函数中使⽤。因为:必须要通过锁对象调⽤这2个⽅法。
等待唤醒机制其实就是经典的“⽣产者与消费者”的问题
线程池:其实就是⼀个容纳多个线程的容器,其中的线程可以反复使⽤,省去了频繁创建线程对 象的操作,⽆需反复创建线程⽽消耗过多资源
合理利⽤线程池能够带来三个好处:
1. 降低资源消耗。减少了创建和销毁线程的次数,每个⼯作线程都可以被重复利⽤,可执⾏多个任务。
2. 提⾼响应速度。当任务到达时,任务可以不需要的等到线程创建就能⽴即执⾏。
3. 提⾼线程的可管理性。可以根据系统的承受能⼒,调整线程池中⼯作线线程的数⽬,防⽌因为消耗过多的内存,⽽把服务器累趴下(每个线程需要⼤约1MB内存,线程开的越多,消耗的内存也就越⼤,最后死机)。
使⽤线程池中线程对象的步骤:
1. 创建线程池对象。
2. 创建Runnable接⼝⼦类对象。(task)
3. 提交Runnable接⼝⼦类对象。(take task)
4. 关闭线程池(⼀般不做)。
Executors 类中有个创建线程池的⽅法如下:
public static ExecutorService newCachedThreadPool() 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最⼤数量)
static ExecutorService newSingleThreadExecutor() 创建一个使用从无界队列运行的单个工作线程的执行程序。
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
public Future<?> submit(Runnable task) :获取线程池中的某⼀个线程对象,并执⾏
public void shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。
ScheduledExecutorService类独有的延迟:public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) 创建并执行在给定延迟后启用的单次操作。
Thread 和 Runnable 的区别
如果⼀个类继承 Thread,则不适合资源共享。但是如果实现了 Runable 接⼝的话,则很容易的实现资源共享。
总结:实现 Runnable 接⼝⽐继承 Thread 类所具有的优势:
1. 适合多个相同的程序代码的线程去共享同⼀个资源。
2. 可以避免 java 中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独⽴。
4. 线程池只能放⼊实现 Runable 或 Callable 类线程,不能直接放⼊继承 Thread 的类。
Run方法任何时刻都有可能被打断
优先级只是提升了这个线程的执行概率
GC -> 垃圾回收机制
setDaemon(true):如果 true ,将此线程标记为守护线程。设置守护线程,所有的”前置”线程都结束了,守护线程也结束(当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。)
线程通信 sleep()等待 带着锁 wait()等待会释放锁(别的等待会释放锁)
join(long millis)等待最多millis毫秒(系统过去millis毫秒)后无论之前线程有没有结束,都开始
线程同步:
1. 同步代码块:synchronized 关键字可以⽤于⽅法中的某个区块中,表示只对这个区块的资源实⾏互斥访问
2. 同步⽅法:使⽤ synchronized 修饰的⽅法,就叫做同步⽅法,保证A线程执⾏该⽅法的时候,其他线程只能在⽅法外等着。
3. 锁机制:java.util.concurrent.locks.Lock 机制提供了⽐synchronized代码块和synchronized⽅法更⼴泛的锁定操作,同步代码块/同步⽅法具有的功能Lock都有,除此之外更强⼤,更体现⾯向对象。
Lock锁也称同步锁,加锁与释放锁⽅法化了,如下:
public void lock() :加同步锁。 public void unlock() :释放同步锁。
线程通信: 等待唤醒机制 wait/notify 就是线程间的⼀种协作机制。
调⽤wait和notify⽅法需要注意的细节:
1. wait⽅法与notify⽅法必须要由同⼀个锁对象调⽤。因为:对应的锁对象可以通过notify唤醒使⽤同⼀个锁对象调⽤的wait⽅法后的线程。
2. wait⽅法与notify⽅法是属于Object类的⽅法的。因为:锁对象可以是任意对象,⽽任意对象的所属类都是继承了Object类的。
3. wait⽅法与notify⽅法必须要在同步代码块或者是同步函数中使⽤。因为:必须要通过锁对象调⽤这2个⽅法。
等待唤醒机制其实就是经典的“⽣产者与消费者”的问题
线程池:其实就是⼀个容纳多个线程的容器,其中的线程可以反复使⽤,省去了频繁创建线程对 象的操作,⽆需反复创建线程⽽消耗过多资源
合理利⽤线程池能够带来三个好处:
1. 降低资源消耗。减少了创建和销毁线程的次数,每个⼯作线程都可以被重复利⽤,可执⾏多个任务。
2. 提⾼响应速度。当任务到达时,任务可以不需要的等到线程创建就能⽴即执⾏。
3. 提⾼线程的可管理性。可以根据系统的承受能⼒,调整线程池中⼯作线线程的数⽬,防⽌因为消耗过多的内存,⽽把服务器累趴下(每个线程需要⼤约1MB内存,线程开的越多,消耗的内存也就越⼤,最后死机)。
使⽤线程池中线程对象的步骤:
1. 创建线程池对象。
2. 创建Runnable接⼝⼦类对象。(task)
3. 提交Runnable接⼝⼦类对象。(take task)
4. 关闭线程池(⼀般不做)。
Executors 类中有个创建线程池的⽅法如下:
public static ExecutorService newCachedThreadPool() 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最⼤数量)
static ExecutorService newSingleThreadExecutor() 创建一个使用从无界队列运行的单个工作线程的执行程序。
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
public Future<?> submit(Runnable task) :获取线程池中的某⼀个线程对象,并执⾏
public void shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。
ScheduledExecutorService类独有的延迟:public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) 创建并执行在给定延迟后启用的单次操作。