8/17 学习博客 多线程的基本知识
进程包含一个或多个线程,进程是资源调度的基本单位,线程是执行调度的基本的单位。线程的创建和销毁效率都比进程高。Java开发一般就是线程为主。
线程的几种常用创建方式:
比如:
1.继承Thread类重写run方法。
2.实现Runnable接口 重写run方法。
3.继承Thread类重写run方法,用内部隐藏函数。
4.实现Runnable接口 重写run方法,用内部隐藏函数。
5.lambda表达式 ()->{}
还有等等
线程的几种特性就是 id name 优先级 状态 是前台线程还是后台线程
其中前台线程会影响进程的结束,后台线程就不会。默认创建的都是前台线程
通过
t.setDaemon(true);
//设置t为后台线程
java线程终止是通过加快run方法的执行来的,有强制结束的方法但不建议 所以我们就通过标志符来判断run方法什么时候结束
1.我们自己手动设置比如isQuit = false 然后 while(!isQuit){ 这样来判断
对于lambda表达式创建 有需要注意的点:
就是lambda有个捕获变量 作用域是到上一类,所以如果()里面用的变量是被捕获的,那么这个变量他要求是final 不可修改 。 所以我们的isQuit要作为一个成员变量,那么这样lambda他就不是访问捕获变量的语法了,就不受final限制。
2.Thread内部有一个现场标志位,用于判断是否结束 通过t.interrupt(); 来终止
需要注意的是 如果只是单纯的interrupt
该线程还是会继续运行, 假装没听见 所以我们需要加一个break来彻底终止
Thread t = new Thread(()->{
//Thread内部有一个现场标志位,用于判断是否结束
while(!Thread.currentThread().isInterrupted()){
System.out.println("线程工作中");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//做一些其他工作完成之后在结束
System.out.println("其他操作");
break;
}
}
});
t.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("让t线程终止");
t.interrupt();
}
t.join() 让主线程阻塞等待t线程的执行完毕
接着线程安全问题
就比如count++ 在cpu里面是分为3个步骤 load内存加载到cpu add加 save保存到内存
这时候两个并发的编程都执行这个count++,由于这个线程调度执行的随机性所以最后就会出现 结果的覆盖丢失。
这就是因为这个++在cpu不是原子操作
这也说明引发线程安全的两个原因
1.最主要就是线程调度执行的随机性(抢占式)
2.两个线程对同一变量做修改。
解决的话就是通过加锁方式来保障原子性
这里就通过synchronized锁 (要注意synchronized后括号里的对象要是同一个)
这样 锁对象一样才会触发锁竞争,不同则依旧并行
锁竞争就是 t1先加锁在执行的时候,t2也访问这个资源同时就触发了锁竞争,t2的lock操作就会阻塞到t1的unlock操作后才能执行完毕

浙公网安备 33010602011771号