* 进程和线程
* (应用程序的执行实例)--》 进程 《--(有独立的内存空间和系统资源)
* (CPU调度和分派的基本单位) 线程 《--(进程中执行运算的最小单位,可完成一个独立的顺序控制流程)
*
* 多线程
* 什么是多线程
* 如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”
* 多个线程交替占用CPU资源,而非真正的并行执行
* 多线程好处
* 充分利用CPU的资源
* 简化编程模型
* 带来良好的用户体验
* 线程的状态:
*(1)、创建状态
*(2)、就绪状态
*(3)、阻塞状态
*(4)、运行状态
*(5)、死亡状态
*
* 主线程
* Thread类
* Java提供了java.lang.Thread类支持多线程编程
* 主线程
* main()方法即为主线程入口
* 产生其他子线程的线程
* 必须最后完成执行,因为它执行各种关闭动作
* 示例:
* public static void main(String args[]) {
Thread t= Thread.currentThread();
System.out.println("当前线程是: "+t.getName());
t.setName("MyJavaThread");
System.out.println("当前线程名是: "+t.getName()); }
*
* 线程的创建和启动
* 在Java中创建线程的两种方式
* 继承java.lang.Thread类
* 实现java.lang.Runnable接口
* 使用线程的步骤
* 1、定义线程-->2、创建线程对象-->3、启动线程-->4、终止线程
*
* 继承Thread类创建线程2-1
* 定义MyThread类继承Thread类
* 重写run()方法,编写线程执行体
* 创建线程对象,调用start()方法启动线程
*
* run()方法和start()方法的区别
* 1)run()线程体:每个线程对象都要执行的
* 2)start()线程的启动方法,启动之后线程进入就绪状态,通过
抢占CPU资源来执行线程任务
*
public class MyThread extends Thread{
//重写run()方法
public void run(){
for(int i=1;i<100;i++){
System.out.println(
Thread.currentThread().getName()+":"+i);
}}}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); //启动线程
}
* 继承Thread类创建线程2-2
* 多个线程交替执行,不是真正的“并行”
* 线程每次执行时长由分配的CPU时间片长度决定
*
* 常见问题
* 启动线程是否可以直接调用run()方法?
* 调用run():
* 只有主线程一条执行路径
* 调用start()
* 多条执行路径,主线程和子线程并行交替执行
*
* 实现Runnable接口创建线程
* 定义MyRunnable类实现Runnable接口
* 实现run()方法,编写线程执行体
* 创建线程对象,调用start()方法启动线程
*
public class MyRunnable implements Runnable{(这里实现Runnable接口)
public void run(){(run()方法中编写线程执行的代码)
for(int i=1;i<100;i++){
System.out.println(
Thread.currentThread().getName()+":"+i);
}}}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();(创建线程对象)
Thread myThread = new Thread(myRunnable);
thread.start(); //启动线程}
* 比较两种创建线程的方式
*
* 继承Thread类
* 编写简单,可直接操作线程
* 适用于单继承
* 实现Runnable接口
* 避免单继承局限性
* 便于共享资源
*
* 线程调度
* 线程调度指按照特定机制为多个线程分配CPU的使用权
* 一些常用方法
*4.1 currentThread():返回对当前正在执行的线程对象的引用。
*4.2 getId():返回此线程的标识符
*4.3 getName():返回此线程的名称
*4.4 getPriority():返回此线程的优先级
*4.5 isAlive():测试这个线程是否还处于活动状态。
* 什么是活动状态呢?
* 活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备运行的状态。
*4.6 sleep(long millis):使当前正在执行的线程以指定的毫秒数“休眠”(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
*4.7 interrupt():中断这个线程。
*4.8 interrupted() 和isInterrupted():
* interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能
* isInterrupted(): 测试线程Thread对相关是否已经是中断状态,但部清楚状态标志
*4.9 setName(String name):将此线程的名称更改为等于参数 name 。
*4.10 isDaemon():测试这个线程是否是守护线程。
*4.11 setDaemon(boolean on):将此线程标记为 daemon线程或用户线程。
*4.12 join():
* 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,
主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,
也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
* join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。
也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行
*4.13 yield():
*yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU时间。
*注意:放弃的时间不确定,可能一会就会重新获得CPU时间片。
*4.14 setPriority(int newPriority)
*
* 线程休眠
* 让线程暂时睡眠指定时长,线程进入阻塞状态
* 睡眠时间过后线程会再进入可运行状态
* public static void sleep(long millis)
* 示例:
public class Wait {
public static void bySec(long s) {
for (int i = 0; i < s; i++) {
System.out.println(i + 1 + "秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}}}}
* 线程的强制运行2-1
* 使当前线程暂停执行,等待其他线程结束后再继续执行本线程
public final void join()
public final void join(long mills)
public final void join(long mills,int nanos)
*
* millis:以毫秒为单位的等待时长
* nanos:要等待的附加纳秒时长
* 需处理InterruptedException异常
*
* 线程的强制运行2-2
*
public static void main(String[] args) {
Thread temp = new Thread(new MyThread());
temp.start();
for(int i=0;i<20;i++){
if(i==5){
try {
temp.join();---》(阻塞主线程,子线程强制执行)
} catch (InterruptedException e) {
e.printStackTrace(); }}
System.out.println(Thread.currentThread().getName()+"运行:"+i);
}
//省略代码…
}
* 线程的礼让2-1
* 暂停当前线程,允许其他具有相同优先级的线程获得运行机会
* 该线程处于就绪状态,不转为阻塞状态
* public static void yield()
* 只是提供一种可能,但是不能保证一定会实现礼让
* 示例:
public class MyThread implements Runnable{
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().
getName()+"正在运行:"+i);
if(i==3){
System.out.print("线程礼让:");
Thread.yield();
} } }}
*
*
* 同步方法2-1
* 使用synchronized修饰的方法控制对类成员变量的访问
* 访问修饰符 synchronized 返回类型 方法名(参数列表){……}
* 或者
* synchronized 访问修饰符 返回类型 方法名(参数列表){……}
* 注意:synchronized就是为当前的线程声明一把锁
* 示例:
// 同步方法:售票
public synchronized void sale() {
if (count <= 0) {
flag = true;
return;
}
// 省略代码:修改数据
// 省略代码:显示信息
}
* 同步代码块2-1
synchronized(syncObject){
//需要同步的代码
}
* syncObject为需同步的对象,通常为this
* 效果与同步方法相同
public void run() {
while (true) {
synchronized (this) { //同步代码块
// 省略修改数据的代码......
// 省略显示信息的代码......
}}}
*
* 多个并发线程访问同一资源的同步代码块时
* 同一时刻只能有一个线程进入synchronized(this)同步代码块
* 当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
* 当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码
*
* 线程安全的类型
* 查看ArrayList类的add()方法定义
public boolean add(E e) {
ensureCapacityInternal(size + 1); (集合扩容,确保能新增数据)
elementData[size++] = e; (在新增位置存放数据)
return true;
}
* ArrayList类的add()方法为非同步方法
* 当多个线程向同一个ArrayList对象添加数据时,可能出现数据不一致问题
* 提示: ArrayList为非线程安全的类型
*
* 线程安全的类型
*
*-------------------------------------------------------------------------------------|
* | 方法是否同步 | 效率比较 | 适合场景 |
*-------------------------------------------------------------------------------------|
* 线程安全 | 是 | 低 | 多线程并发共享资源|
*-------------------------------------------------------------------------------------|
* 非线程安全 | 否 | 高 | 当线程 |
*-------------------------------------------------------------------------------------|
* 为达到安全性和效率的平衡,可以根据实际场景来选择合适的类型
*
*
* 常见类型对比2-1
* Hashtable && HashMap
* Hashtable
* 继承关系
* 实现了Map接口,Hashtable继承Dictionary类
* 线程安全,效率较低
* 键和值都不允许为null
* HashMap
* 继承关系
* 实现了Map接口,继承AbstractMap类
* 非线程安全,效率较高
* 键和值都允许为null
* StringBuffer && StringBuilder
* 前者线程安全,后者非线程安全
*