1.主线程:执行主(main)方法的线程
单线程程序:java程序中只有一个线程,执行从main方法开始,从上到下依次执行,JVM执行main方法,main方法会进入到栈内存,JVM会找操作系统开辟一条main方法通向CPU的执行路径,CPU就可以通过这个路径来执行main方法,而这个路径就叫main(主)线程。
2.创建多线程程序的第一种方式:创建Thread类的子类
Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类
实现步骤:
1.创建一个Thread类的子类
2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么?)
3.创建Thread类的子类对象
4.调用Thread类中的star方法,开启新的线程,执行run方法
结果是两个线程并发运行,当前线程(main线程)和另一个线程(创建的新线程,执行其run方法)
多次启动一个线程是非法的,特别是当线程执行结束后,不能再重新启动
java属于抢占式调度,哪个线程优先级高,哪个线程优先执行,同一个优先级,随机一个执行
3.创建多线程程序的第二种方式:实现Runnable接口
实现步骤:
1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法,设置线程任务
3.创建Runnable接口的实现类对象
4.创建Thread对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类中的start方法,开启新的线程,执行run方法
实现Runnable接口创建多线程的好处:
1.避免了单继承的局限性
一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他类
实现了Runnable接口还可以继承其他类,实现其他的接口
2.增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离
实现类中,重写run方法:用来设置线程任务
创建Thread类对象调用start方法:用来开启新线程
-
匿名内部类方式实现线程的创建
匿名:没有名字
内部类:写在其他类内部的类匿名内部类作用:简化代码
把子类继承父类,重写父类的方法,创建子类对象合成一步完成
把实现类实现接口,重写接口中的方法,创建实现类的对象合成一步完成匿名内部类最终产物:子类/实现类对象,而这个类没有名字
格式:
new 父类/接口(){
重复父类/接口中的方法
}
1).
//线程的父类是Thread
//new MyThread().start();
new Thread(){
//重写run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"程序猿");
}
}
}.start();
2).
new Thread(new Runnable(){
//重写run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"程序员");
}
}
}).start();
-
进入到TimeWaiting(计时等待)的两种方式
1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
2.使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入到Runnable/Blocked状态唤醒的方法:
notify(),唤醒在此对象监视器上等待的单个线程
notifyAll(),唤醒在此监视器上等待的所有线程
例:
//创建锁对象保证唯一
Object obj=new Object();
//创建一个顾客线程
new Thread(new Runnable() {
@Override
public void run() {
//保证等待和唤醒只能有一个在执行
synchronized (obj){
System.out.println("告知老板要的包子种类和数量");
//调用wait方法,放弃cpu的执行,进入到WAITTING状态
try {
obj.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子开吃");
}
}
}).start();