创建多线程
一个程序同时执行多个任务,每一个任务称为一个线程。多线程与多进程的本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。
两种实现方式:
①继承Thread类;重写run方法;构造一个子类对象,并调用start方法
class MyThread extends Thread {
@Override
public void run() {
//...要做的事
}
}
//调用
Thread myThread1 = new MyThread(); // 创建一个新的线程 myThread1 此线程进入新建状态
Thread myThread2 = new MyThread(); // 创建一个新的线程 myThread2 此线程进入新建状态
myThread1.start(); // 调用start()方法使得线程进入就绪状态
myThread2.start(); // 调用start()方法使得线程进入就绪状态
}
}
}
②实现Runnable接口;重写run方法;由Runnable创建Thread对象;启动线程;
class MyRunnable implements Runnable {
@Override
public void run() {
//...要做的事
}
}
//调用
Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
Thread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程
Thread thread2 = new Thread(myRunnable);
thread1.start(); // 调用start()方法使得线程进入就绪状态
thread2.start();
线程状态
线程一共有六种状态:
- New新建
- Runnable可运行
- Blocked被阻塞
- Waiting等待
- Timed waiting计时等待
- Terminated被终止
当用操作符new创建一个新线程时,就是处于新建状态;
一旦调用start方法,线程就会处于Runnable状态,该状态的线程可能正在运行也可能没有运行,所有称之为可运行状态,而不是运行状态;
当线程试图获取一个内部的对象锁,而该锁被其他线程持有–阻塞;当线程等待另一个线程通知调度器一个条件时—等待;方法有超时参数是,调用他们进入计时等待;
当run方法正常退出或者因为一个没有捕获的异常意外终止;(stop方法可以杀死线程,但是已过时,不建议使用)
线程状态及转换如图:
线程属性
线程优先级
在java中每个线程都有优先级(1-10)默认为5。当有机会选择调用时,优先级高的先调用。
setPriority(int p) 设置优先级
yield() 线程让步, 当其他线程优先级大于等于它时,就先执行。守护线程
通过t.setDaemon(true);将线程转换为守护线程,需要在线程启动之前调用,唯一的用途就是给其他线程提供服务,如(计时线程)未捕获异常处理器
run方法不能抛出任何受检异常,但非受检异常会终止线程,不需要catch,终止前会被传递到未捕获异常处理器,通过setDefaultUncaughtExceptionHandler方法安装默认处理器- 线程组
……
同步
两个或两个以上的线程需要共享对同一数据的存取,为避免多线程引起的对共享数据的差错,必须使用同步。
有两种机制可以防止代码块受并发访问的干扰。
synchronized关键字
介绍一下锁;锁是用来保护代码片段,锁可以拥有一个或多个相关的条件对象,Lock和Condition接口提供高度的锁定机制。然而并不需要这样完全控制,实际上每个对象都有一个内部锁,如果方法用sy..ed关键字声明,那么对象锁会保护整个方法。使用
多数情况下可以使用java.util.concurrent包中的机制;
其次考虑使用synchronized关键字;
特殊情况下使用Lock/Condition