多线程(未完)
多线程
线程的基础知识
- 有多条顺序执行流。可以理解为,一个程序中,有多个main方法在同时执行.
理解线程和进程的区别与联系
- 进程>线程,一个进程中可以包含多个线程。
- 进程可以宽泛的理解为一个程序,一个程序即为一个进程(goole,tim)
区分表
| 线程 | 进程 |
|---|---|
| 并行 | 并发 |
| 短时间内多个线程轮换执行 | 多个进程同时执行 |
两种创建线程的方式
1.继承Thread类创建线程
- 通过该方法创建多线程,每个对象都需要继承Thread类,并且实现run方法
public class FirstThread extends Thread{
private static int i ;
@Override
public void run() {
for (int i=0;i<20000;i++){
System.out.println(this.getName() + ":" + i);
}
}
public static void main(String[] args) {
long l =System.currentTimeMillis();
// FirstThread f = new FirstThread();
// f.start();
// f.start();
// 会抛出IllegalThreadStateException异常
/*一个对象不能重复调用start*/
new FirstThread().start();
new FirstThread().start();
//程序正常执行
}
}
实现Runnable接口创建线程
- 定义类实现Runnable需要,实现Runable接口,并重写run方法,该run方法的方法体
public class SecondThread implements Runnable {
private int i = 0;
@Override
public void run() {
for (;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
for (int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
if (i==20){
SecondThread st = new SecondThread();
new Thread(st,"新线程1").start();
new Thread(st,"新线程2").start();
}
}
}
}
线程的run()方法和start()方法的区别和联系
- run()方法仅仅是一个方法,用对象实例调用run方法,仅仅就是在执行一个方法
- start()方法,则会开辟一条线程
线程的生命周期
- 新建
- 当程序用new新建了一个线程之后,该线程就处于新建状态
- 就绪
- 当线程调用了start方法之后,该线程处于就状态(如果调用run方法,该线程将取消就绪状态,请更换对象调用start)
- 运行
- 处于就绪状态的线程,在获得了cpu处于运算状态的时候,该线程处于运行状态
- 阻塞
- 线程调用sleep方法
- 调用了一个阻塞式的io方法
- 线程试图获得一个同步监视器
- 线程在等待某个通知
- 程序调用了notify方法将该线程挂起
- 死亡
- run或者call方法执行完成
- 选不出各部分抛出一个未捕获的exception或者Error
- 直接调用stop
线程已死亡,重新start或者,一个新建对象两次start都是错误的
控制线程的常用方法
- join线程
- 等待被join的线程执行完毕,请不要在被join线程中调用join,可能会造成锁死
public static int i =0;
public void run() {
for ( ;i<100;i++){
System.out.println(Thread.currentThread().getName() + " "+i);
if (i==50){
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
JoinTest jt = new JoinTest();
Thread t = new Thread(jt,"1");
t.setDaemon(true);
t.start();
for ( ;i<100;i++){
System.out.println(Thread.currentThread().getName() + "" +i);
}
}
- sleep,线程睡眠
- 指定线程暂停
- yoeld,线程让步
- 只有在其他线程的优先级,比使用该方法线程的优先级高或者相同,该方法生效
- 改变线程优先级
- Thread提供SetPriority、getProiority,来修改线程的优先级(整数1-10)
线程同步的概念和必要性
-
多个线程修改同一数据,会造成错误
例子 :x1 ---线程一
x2 ---线程二
b ---- a对象的一个方法,操作a对象的值d
d ---- a对象的一个值----10,这个值必须大于0
x1,x2同时通过b方法修改d,已知,如果d的值不为10就不能修改
两个线程的作用相同,将这个值减去10
x1 x2同时执行 -
步骤
- x1 判断d为10 通过b方法
- x2 判断d为10 通过b方法,此时,x1线程还未来得及修改数值造成,x2 同样进入该方法的操作代码中
- x1 d-10 = 0 d = 0; 操作a对象的值d成功
- x1 线程结束
- x2 d-10 = -10 d = -10 操作a对象的值d成功
- x2 线程结束
结果很明了,d=-10,超出正常范围
-
加锁之后的步骤:
- 步骤
- x1 判断d为10 a对象的该方法上锁
- x2 a对象的b方法上锁,线程处于就绪阻塞状态
- x1 d-10 = 0 d = 0; 通过a对象的b方法成功操作值为d
- x1 线程结束
- x2 进入b方法判定 d!=10 x2跳过该方法
- x2 线程结束
综上所知,线程
-
同步代码块的原理
- 同步监视器():任何一个时刻,只能有一个线程获得最同步监视器的锁定。其他线程不能访问。
- 释放同步监视器锁定:在代码块执行完成、抛出未捕获异常或者错误、同步代码块出先break、return、执行了同步监视器的wait方法。
- 不会释放:sleep、yield、其他线程调用该线程的suspend。
使用synchronized控制线程和同步
- synchronized块
synchronized(){
}
- synchronized方法
public synchronized void m(){
}
使用Lock对象控制线程同步
private final ReentrantLock lock = new ReentrantLock(); //声明lock锁
使用Object提供的方法实现线程通信
使用管道流实现,线程通信
实现Callable接口实现创建线程
线程池的功能和用法
java8增强的ForkJoinPool
ThreadLocal类功能的用法
使用线程安全的集合类
白茶清欢无别事,我在等风也等你。

浙公网安备 33010602011771号