叨逼叨两句
- 哈哈哈哈哈哈哈哈哈哈哈哈
- 今天了结了一个心结,瞬间整个人的时不时涌现的恐慌情绪都解除了,没了这个后顾之忧分心,瞬间学习专注力爆表啊!!!果然,我只要没有特别大的让我分心的琐事,专注一件事的能力就是很强很强很强!!!当年读书时总能后期大爆发迎头赶上,看来也不是没有原因的。
- 我记忆力不算特别强,也就比均值高一点,80分样子,但是我的专注力极强,我有信心自己是那前5%的人。
- 今天学的内容我感觉特别high,一方面老师讲的好,另一方面是这些内容涉及计算机底层原理,让我在计算机这个黑箱上戳了个小洞,满足了我的好奇心。
- 之后项目之余,我要好好看看这些底层原理的书,就看着玩,不求甚解。
24-01:多线程的引入
-
什么是线程
- 线程是程序执行的一条路径,一个进程中可以包含多条线程。
- 多线程并发执行可以提高程序的效率,可以同时完成多项工作。
- 多线程原理
24-02:多线程的并行与并发
- 并行:两个任务同时进行【需要多个CPU】
- 并发:两个任务都请求CPU处理,而CPU同一时间只能接受一个任务,就把这两个任务安排轮流进行,由于CPU切换时间极短,处理速度极快,会让人感觉两个人任务同时在运行。
24-03:Java程序运行原理和JVM的启动是多线程的吗?
-
Java程序的运行原理
- Java命令会启动Java虚拟机。启动JVM就等于启动了一个应用程序,也就是启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法。
-
JVM的启动是多线程的吗?
- 是,JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
package com.test.demo001; public class Demo015 { public static void main(String[] args) { for(int i = 0; i < 10000000; i++){ new Demo(); } } } class Demo { public void finalize(){ System.out.println("垃圾已经回收"); } }
24-(04-06):多线程程序实现的两种方法
方法1
-
继承Thread
- 定义一个类继承Thread
- 重现run方法
- 把新线程要做的事写在run方法中
- 创建线程对象
- 开启新线程,内部会自动执行run方法【start就想百米赛跑的发令枪,一开枪,各个线程就像各个赛道的运动员一样开始跑了(CPU轮流处理)】
package com.test.demo001;
public class Demo015 {
public static void main(String[] args) {
Demo d = new Demo();
d.start();
for (int i = 0; i < 1000; i++) {
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
}
class Demo extends Thread{
public void run(){
for(int i = 0; i < 1000; i++){
System.out.println("bbbbbb");
}
}
}
方法2
-
实现Runnable
- 定义类实现Runnable接口
- 实现run方法
- 把新线程要做的事写在run方法中
- 创建自定义的Runnable的子类对象
- 创建Thread对象,传入Runnable
- 调用start()开启新线程,内部会自动调用Runnable的run()方法
package com.test.demo001;
public class Demo015{
public static void main(String[] args) {
Demo d = new Demo();
Thread t = new Thread(d);
t.start();
for(int i = 0; i < 1000; i++){
System.out.println("bbb");
}
}
}
class Demo implements Runnable{
public void run(){
for(int i = 0; i < 1000; i++){
System.out.println("aaaaaaaaaaaaaa");
}
}
}
-
实现Runnable的原理
根据源码可知:
- Thread有一个构造函数,接收Runnable类型的参数
- 该构造函数接收参数后,最终这个参数会传给Thead对象的一个Runnable类型的成员变量(变量名为 target)。
- 当你用Thread对象调用start方法时,它会调用Thread对象的run方法
- 当Thread对象的run方法被调用时,它将执行target的run方法,而这个target的run方法,就是你那个实现了Runnable的类的run方法。
24-07:两种方式的区别
-
查看源码的区别:
- 继承Thread:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法。
- 实现Runnable:构造函数中传入了Runnable的引用,成员变量记住了它,start()调用run()方法时,内部判断成员变量Runnable的引用若不为null,它就将执行实现了Runnable接口的这个子类的run()方法。
-
继承Thread【开发推荐】
- 优点:可以直接使用Thread类中的方法,代码简单
- 缺点 :如果已经有了父类,就不能用这种方法
-
实现Runnable接口
- 优点:即使自己定义的线程有了父类也木有关系,依然可实现Runnable接口。
- 缺点:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂。
24-08:匿名内部类实现线程的两种方式
-
继承Thread类
package com.test.demo001; public class Demo015{ public static void main(String[] args) { new Thread(){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println("bbbbbbbbbbbbb"); } } }.start(); for(int i = 0; i < 1000; i++){ System.out.println("aaaa"); } } }
-
实现Runnable接口
package com.test.demo001; public class Demo015{ public static void main(String[] args) { new Thread( new Runnable(){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println("bbbbbbbbbbbb"); } } } ).start(); for(int i = 0; i < 1000; i++){ System.out.println("aaaa"); } } }
24-09:获取名字和设置名字
-
获取名字
- 通过getName()方法获取线程对象的名字【Thread类有默认的名字,但你也可以自己修改】
package com.test.demo001; public class Demo015{ public static void main(String[] args) { new Thread(){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println(this.getName()+".......bbbbbbbbbbbbbb"); } } }.start(); new Thread(){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println(this.getName()+".......aa"); } } }.start(); } }
-
设置名字
- 通过构造函数可以传入String类型的名字
package com.test.demo001; public class Demo015{ public static void main(String[] args) { new Thread("NB"){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println(this.getName() + ".......bbbbbbbbbbbbbb"); } } }.start(); new Thread("SB"){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println(this.getName() + ".......aa"); } } }.start(); } }
- 通过setName(String)方法可设置线程对象的名字
package com.test.demo001; public class Demo015{ public static void main(String[] args) { new Thread(){ public void run(){ this.setName("NB"); for(int i = 0; i < 1000; i++){ System.out.println(this.getName() + ".......bbbbbbbbbbbbbb"); } } }.start(); new Thread(){ public void run(){ this.setName("SB"); for(int i = 0; i < 1000; i++){ System.out.println(this.getName() + ".......aa"); } } }.start(); } }
package com.test.demo001; public class Demo015{ public static void main(String[] args) { Thread t1 = new Thread(){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println(this.getName() + ".......bbbbbbbbbbbbbb"); } } }; Thread t2 = new Thread(){ public void run(){ for(int i = 0; i < 1000; i++){ System.out.println(this.getName() + ".......aa"); } } }; t1.setName("NB"); t2.setName("SB"); t1.start(); t2.start(); } }
24-10:获取当前线程
Thread.currentThread()
- 继承Thread的方式不用使用这个方法,实现Runnable接口的方式需要使用。
package com.test.demo001;
public class Demo015{
public static void main(String[] args) {
new Thread(){
public void run(){
for(int i = 0; i < 1000; i++){
System.out.println(this.getName() + ".......bbbbbbbbbbbbbb");
}
}
}.start();
new Thread(
new Runnable(){
public void run(){
for(int i = 0; i < 1000; i++){
System.out.println(Thread.currentThread().getName()+ "....aa");
}
}
}
).start();
}
}
- 主线程也能这样获取
package com.test.demo001;
public class Demo015{
public static void main(String[] args) {
//Thread.currentThread().setName("NB");
System.out.println(Thread.currentThread().getName());
}
}
24-11:休眠线程
- sleep()
1秒=1000毫秒=1000*1000微秒=1000*1000*1000纳秒
package com.test.demo001;
public class Demo015{
public static void main(String[] args) throws InterruptedException {
for(int i = 10; i >= 0; i--){
Thread.sleep(1000);
System.out.println(i);
}
}
}
- CPU遇见一个sleep()就会先不执行这一个,而改去执行另一个,直到sleep的时间结束。【之后还会学一个wait方法,这个是没有时间限制的】
package com.test.demo001;
public class Demo015{
public static void main(String[] args) throws InterruptedException {
new Thread(){
public void run(){
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(".......aaaaaaaaaaaa");
}
}
}.start();
new Thread(){
public void run(){
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(".......bb");
}
}
}.start();
}
}