java----线程
《基础概念》
并发:正如我们一边打电话一边开车,大脑的注意力是不断切换的,只是大脑切换的速度很快,所以看起来我们是同时打电话+开车
《线程基本使用》
《继承Thread类,重写run方法》
《为什么不直接调用run方法而是调用start方法?》
调用start方法后底层会调用start0方法
《实现Runnable接口,重写run方法》
注意为什么要通过实现Runnable接口,重写run方法来实现创建线程的原因
《线程不安全》
《问题引出》
模拟售票系统:
但是最后却有这样一种现象,明显是不合理的
这是因为可能多个线程同时绕过if 判断导致;
《解决----线程同步》
这样就解决了上面的问题
多个线程是抢夺同一个锁(同一个对象)才能达到效果
如果上面写成:
就会造成如下等不好的影响:
《线程退出》
上面的操作是在main线程中发通知给thread00线程让其终止
《线程常用方法》
《守护线程》
在一般情况下,比如我在主线程中开启了一个子线程(t),如果主线程结束,子线程还未结束,那么子线程是不会结束的
为了让子线程跟随主线程共同结束,可以将子线程设置为守卫线程: t.setDaemon(true);
《线程的生命周期》
Thread.State是枚举类说明可以直接:Thread.State.NEW来表示其生命周期
通过 t.getState() 可以得到现在线程的状态(t是线程)
《线程死锁》
像这样写会造成经典的死锁
因为o1与o2是静态的,则即使在外面创建了两个对象也都是同一个o1,o2;
两个线程,一个线程flag=true,一个线程flag=fasle;
一个线程得到了o1的互斥锁,一个线程得到了o2的互斥锁
再深入后,得到了o1的互斥锁的线程要o2的互斥锁才能进行,另一个同理
这样两个就卡住了,造成死锁
1 public class Test06 {
2 public static void main(String[] args) {
3 new Thread(new Tthread(true)).start();
4 new Thread(new Tthread(false)).start();
5 }
6 }
7
8 class Tthread implements Runnable {
9 private static Object o1 = new Object();
10 private static Object o2 = new Object();
11 private boolean flag;
12
13 public Tthread(boolean flag) {
14 this.flag = flag;
15 }
16
17 @Override
18 public void run() {
19 block();
20 }
21
22 private void block() {
23 if (flag) {
24 synchronized (o1) {
25 System.out.println(Thread.currentThread().getName() + "进入到o1的互斥锁"
26 + "尝试进入o2的互斥锁");
27 synchronized (o2) {
28 System.out.println(Thread.currentThread().getName() + "进入到o2的互斥锁");
29 }
30 }
31 } else {
32 synchronized (o2) {
33 System.out.println(Thread.currentThread().getName() + "进入到o2的互斥锁"
34 + "尝试进入o1的互斥锁");
35 synchronized (o1) {
36 System.out.println(Thread.currentThread().getName() + "进入到o1的互斥锁");
37 }
38 }
39 }
40
41 }
42 }
结果:
就这样不动了
《释放锁》
《日后学习对线程的理解》
《为什么在执行单一的任务的时候(比如都是for循环)多线程会比单线程慢?》
参考博客:https://blog.51cto.com/u_12630471/3698074
比如在一些情况下:
我要运行一个程序,其有我输入数据,cpu处理数据,输出数据的过程,这个时候
多线程程序可能比单线程更快
因为如果在单线程的情况下Cpu在处理完数据后就闲置了,花了大量时间在IO操作(IO操作与CPU无关)上,
但是多线程可以利用处理IO操作的时间处理更多数据
如果是像下面单一的for循环任务,cpu无闲置时间,那么单线程速度更快
《对于多线程上一些奇特的现象的理解》
《一些语法上的问题》
synchronized(D){S};中的D是我们要上锁的资源,即大家都要抢的资源,其可以是
任何对象,但不能使基本数据类型
《对于临界资源的讲解》
synchronized(D){S;}中的D是临界资源,其实还可以写成synchronized xxx f(){};这种方法的形式
不过这个方法要写在临界资源类中,没错,如果写成方法那么临界资源要专门写成一个类
其中执行的语句是原子级的,所谓原子级是指相关操作是连在一起的,不可分割的,只要少的其中一个操作,那么就执行有缺陷
《线程的同步机制》
同步:线程间执行需要遵守某种约定,java实现同步的方法是:互斥+通信
所谓通信是告诉其他线程自己好了(notify()),然后自己等待(wait())...............这样直到任务结束
像notify(),wait()必须直接或间接的作用域于临界区中,否则会异常
wait()会自己主动释放锁,notify()会激活在临界资源等待队列中的线程;
wait()和notify()都是由临界资源发出
《注意点》
wait(),notify(), notifyAll()都是Object中的方法,而且都会抛出异常
我想说的一点事在用到wait(),notify()..........的地方不一定要用到synchronized之类的