多线程
多线程:使计算机的操作系统可以在同一时间执行多个任务
操作系统级别任务就是一个应吹涡皋陕用程序。每一个任务又成为一个进程
对于一个程序而言,也可能同时运行多个任务,那么每个任务成为一个线程。
并发:
进程或线程是并发运行的
os将时间分成若干段,并分配给每个线程或进程,得到时间片段的进程将得到cpu执行,
微观上:进程线程是走走停停的,宏观上是同时执行的,这种现象成为并发
线程运行机制:
但我们调用start()方法时,该线程会向线程调度注册当前线程,只有注册了,才有机会分配到时间片进行并发运行,
不要调度run()方法,若直接调用那么就不是并发的了,而变成同步调用的了,有先后顺序!
时间片段是不均匀的,每个线程分配的时间不是相等的,线程机制尽可能的均匀的将时间片分配不同的线程,
让他们都有机会得到cpu的运行。对于线程运行机制,我们的程序对具体时间片段分配给那个线程都是不可控的
静态内部类不能直接引用外部类的非静态的方法属性,只能用外部类的静态方法或属性
实例化静态内部类
A.B b= new A.B();
pubic class A {
public static class B{
}
}
非静态内部类
pubic class A {
public class B{
}
}
非静态内部类可以引用外部类的方法和属性
A a = new A()
B b = a.new B()
线程的启动和关闭
start():
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。
多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
stop():
关闭线程的方法,不建议使用,不安全
停止线程的方法应该是让run()正常执行完毕
线程运行过程经常会出现类未捕获的异常,该线程会立即终止,但是不会影响当前进程中其他线程的工作
若当前进程中的所有的线程都终止了,那么进程终止!
当我们的程序启动时,操作系统分配一个进程来运行我们的程序,而该进程会创建一个线程来调用我们的main方法
创建线程的另一方式:
将线程与线程体分开
线程体就是线程要并发执行的逻辑
最好的模式是:线程只关心并发操作,不关心其他,我们应将线程与线程体两者解耦
解耦:解除依赖关系,自己关心自己的事情
单独定义线程体
Runnable接口
该接口应用于描述可执行的逻辑,一般描述的就是线程体
线程进入死亡状态后,不要在调度start()
于线程生命周期相关的方法:
static void yield();
主动放弃当次时间片段,进入Runnable状态,等待下一次分配时间片。主动离开Running状态
static void sleep(long time);
从可运行状态running主动进入block状态
阻塞time毫秒后自动回到runnable状态
若在阻塞过程中被打断睡眠阻塞会引发InterruptException
void interrupt();
中断线程
线程的优先级:
线程优先级高的线程被分配的时间段的机率比较高,换句话说,就是被cpu
执行的次数多。但这不是绝对的,毕竟线程调度分配的时间片段是不可控的。
守护线程:
又叫后台线程,
守护线程的特点:
当进程中的所有前台线程都终止后,守护线程强制终止。当进程中只剩下守护线程时,进程终止
后台线程是在线程启动前通过方法设置的
setDaemon(boolean on) on为true设置为后台线程,
设置后台线程必须要在线程调用start()方法之前进行!
线程安全问题:
当多线程共享同一数据时,就可能引发线程安全问题。
synchronized关键字
synchronized可以修饰方法,也可以以独立代码块的形式存在
若修饰方法则方法同步,多线程不能同时访问该方法
若synchronized修饰方法,那么当一个线程进入该方法后,
会对当前方法所属的对象枷锁,那么其他线程访问该对象的这个方法时就不会进入该方法,在方法外等
直到对象的上的锁被释放
synchronized块范围越小,效率越高!
* 使用同步块,我们要保证被锁的对象在多线程
看到的是同一个,否则起不到同步效果
有效的缩小同步范围,可以提高代码执行效率
StringBulider线程不安全的,适合单线程拼接字符串
StringBuffer线程安全的,适合多线程拼接字符串
两者用法一样
List集合
Vetor 线程安全的集合
ArrayList不是线程安全的
Map集合
HashMap不是线程安全的
HashTable是线程安全的
Collctions有获取线程安全的集合方法
Colections.synchronizedList()
获取一个线程安全的List集合
List list = Colections.synchronizedList()
获取线程安全的Map
Colections.synchronizedMap()
获取线程安全的Set
Colections.synchronizedSet()
wait与notify
这俩个方法不是在Thread中定义的。而是在Object中定义的
当线程A调用B对象wait方法,那么该对象就在B对象上等待,A线程进入wait阻塞.
当线程C调用了B对象wait方法,那么该线程也在B对象上等待
当B对象调用notify方法,那么A或B随即进入Runnable状态开始运行,另外一个仍然处于Wait阻塞.
notifyAll方法可以让当前的对象上等待的所有线程进入runnable状态.