1. Thread创建的写法
1.继承Thread,重写run
2.实现Runnable,重写run
3.继承Thread,重写run,使用内部匿名类
4实现Runnable,重写run,使用内部匿名类
5使用lambda方法
Thread中的一些核心属性和方法
- id
- name
- demon(后台线程)
- isAlive—判断系统内核中的线程是否存在
- start 启动线程
- 线程终止写法isinterruptted(即使出现sleep等阻塞状态也会被提前唤醒)
线程的等待
多个线程,调度的顺序在系统是无序的,通过线程等待就可以将线程结束的顺序确定出来
通过t.join的方法就可以将结束顺序固定
假设在main线程调用t.join,main线程就会等待t,t结束后,main也结束了。
t线程没有结束,join堵塞等待,等到t结束后,join就会解除堵塞状态,继续执行,
。(堵塞:该线程不参与cpu的调度执行,解除堵塞继续执行,线程参与到cpu的调度。)
可以理解为两个线程换为一前一后的一个线程。
同时调用t1.join和t2.join的时候,先执行t1。join等待t1线程执行完毕,结束后继续执行t2。join等待t2结束main就会结束。但是t1和t2的线程是在main执行的时候也在执行,他只是等待结束,并不是有了main执行到了join才开始。
线程是并发执行的
t1 和t2是各自调度各自执行
执行先后顺序/谁先结束,都是不确定只不过上述代码中,t1 sleep 3s, t2 sleep 4s
此时 t1 先结束了t2后结束了
所以在执行main方法的时候会在t1join后再等待大约1s(堵塞在t2),才会结束。如果反过来就会变得t2join后,t1。join直接通过。
join() 死等
join(long mills)等到nms
join(long mills,int naps)等到n毫秒m纳秒。
时间戳:System.currentTimeMills();
通常用sleep方法让他堵塞,防止线程打乱顺序。
在seep的时间到了时候,线程会从堵塞状态恢复到就绪状态。
线程状态
也就是PCB的状态。
1.NEW Thread 对象有了,还没调用 start
系统内部的线程还未创建.
2.TERMINATED 线程已经终止了.
terminated
内核中的线程已经销毁了,
3RUNNABLE 就绪状态.
指的是,这个线程“随叫随到'
a) 这个线程正在 CPU 上执行
b) 这个线程虽然没在CPU 上执行,随时可以调度到 CPU 上执行.
4WAITING
死等 进入的阻塞
5TIMED_WAITING 带有超时时间的等
6BLOCKE
进行锁竞争的时候产生的阻塞
线程安全问题!!![核心& 难点 &考点]
线程 是随机调度,抢占式执行.=>这样的随机性,就会使程序的执行顺序,产生变数 =>不同的结果.
但是有的时候,週到不同的緒果、认为不可接收。这为是bug)
如果不加join,直接打印,由于三个线程完全并发执行
此时就会使 主线程 打印 count 并非是 t1 t2 算完的效果.(类似于 读脏数据了
1)把内存 count 中的数值,读取到 cpu 寄存器中,load
2) 把寄存器中的值,+1,还是继续保存在寄存器中 add
3) 把寄存器上述计算后的值,写回到内存 count 里 save
通过上述执行过程,发现,两次++
最后内存的結果、仍然是1!!!
后一次计算 把前一次计算的结果,覆盖掉
ア!!
由于当前线程执行的顺序不确定,有些执行顺序,加两次,结果正确的有些执行顶序,加两次,最后只增加 1
具体有多少次正确,多少次不正确,随机的!!
因此看到的结果,不是精确的 Sw!!!