Java线程的创建 Java多线程之线程的创建
奥卡姆的剃刀生锈了 人气:0想了解Java多线程之线程的创建的相关内容吗,奥卡姆的剃刀生锈了在本文为您仔细讲解Java线程的创建的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Java线程的创建,java多线程,java创建线程,下面大家一起来学习吧。
一、三种创建方式
基于什么创建 | 创建的方式 |
Thread类 | 继承Thread 类 |
Runnable接口 | 实现Runnable 接口 |
callable接口 | 实现callable 接口 |
二、通过Thread类创建
2.1 步骤
- 自定义线程类继承
Thread
类 - 重写
run()
方法,编写线程执行体(当成main()
方法用) - 创建线程对象,调用
start()
方法启动线程
2.2 案例
- 创建两个线程,其中一个线程打印100以内的偶数,另一个线程打印100以内的奇数
//主方法 public class Demo01 { public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); thread1.start(); thread2.start(); } } //100以内的偶数 class Thread1 extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { if (i%2==0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } } //100以内的奇数 class Thread2 extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { if (i%2!=0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } }
- 也可以使用匿名内部类的方法来实现(线程用过以后就不再用了)
public class Demo02 { public static void main(String[] args) { //打印0~100内的偶数 new Thread(){ @Override public void run() { for (int i = 0; i < 100; i++) { if (i%2==0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } }.start(); //打印0~100内的奇数 new Thread(){ @Override public void run() { for (int i = 0; i < 100; i++) { if (i%2!=0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } }.start(); } }
- 三个窗口同时卖票,票数总共为100张(注意票数应该是静态变量,否则就是没创建一个对象,该对象就有100张票)
public class Test { public static void main(String[] args) { Window w1 = new Window("窗口 1 "); Window w2 = new Window("窗口 2 "); Window w3 = new Window("窗口 3 "); w1.start(); w2.start(); w3.start(); } } class Window extends Thread{ //这里票的数量应该是静态变量,否则每个对象创建后都有100张票,而不是总共100张票 private static int tickets = 100; public Window(String name) { super(name); } @Override public void run() { while (tickets > 0){ tickets--; System.out.println(getName() + "卖出了一张票,剩余票数:" + tickets); } } }
- 注意:这里存在一个线程安全问题未解决,后面将会讲到。如下图所示,刚开始三个线程启动的时候,读取的票数都是100张。
2.3 注意的问题
start()
方法的作用:通过调用自己写的线程类对象的start()
方法,来启动该线程,并调用该线程的run()
方法- 不能通过直接调用
run()
方法的方式启动线程 - 不可以让已经
start()
的线程再次star()
来同时跑两个线程。可以通过新建一个该线程类的对象,然后在对新建的对象start()
三、Thread类中常用的方法
- start()启动当前线程;调用当前线程的
run()
方法 - run():通常需要重写Thread类中的此方法,将创建线程需要执行的操作声明在此方法中(当做
main()
使用) - currentThread():静态方法,返回执行当前代码的线程
- getName():获取当前线程的名字
- setName(String name):设置当前线程的名字
- yield():释放当前CPU的执行权(但也有可能下一刻的执行权又回到了当前线程,主控权还是在CPU手上)
- join():在线程a中调用线程b的
join()
,此时线程a就进入阻塞状态,直到线程b完全执行完之后,线程a在结束阻塞状态 - stop():当执行此方法时,强制结束当前线程(已停用)
- sleep(int millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前进程是阻塞状态
- isAlive():判断当前线程是否存活(线程执行完之前都是存活的)
3.1 案例
- 同样是上面的三个窗口买票的问题,同样是100张票,但使用这种创建方法,tickets可以不使用静态变量
四、通过实现Runnable接口来创建线程
4.1 创建步骤
- 创建一个实现了
Runnable
接口的类 - 实现类去实现
Runnable
接口中的抽象方法:run()
- 创建实现类的对象
- 将此对象作为参数传递到
Thread
类的构造器中,创建Thread
类的对象 - 通过
Thread
类的对象调用start()
- 这里的
start()
首先启动了当前的线程,然后调用了Runnable
类型的target的run()
五、继承Thread类和实现Runnable接口两种方式比较
开发中,优先选择实现Runnable接口的方式创建线程
原因:
- 实现Runnable接口的方式没有类的单继承性的局限性(一个类只能继承一个父类,继承了Thread类就不能在继承其他类了)
- 实现Runnable接口的方式更适合来处理多个线程之间有共享数据的情况
联系:Thread类本身也实现了Runnable接口
相同点:两种方式都需要重写run()
方法,将线程要执行的逻辑声明在run()
方法中
六、线程的优先级设置
调度策略
- 对于同优先级的线程,组成先入先出队列(先到先服务),使用时间片策略
- 对于高优先级,使用优先调度的抢占式模式
线程的优先级分为1~10十个档,其中:
NORM_PRIORITY
:5 —— 普通优先级,即默认的优先级MAX_PRIORITY
:10 —— 最高优先级MIN_PRIORITY
:1 —— 最低优先级getPriority()
:获取线程的优先级setPriority(int p)
:设置线程的优先级
注意:高优先级的线程要抢占低优先级线程CPU的执行权。但是只是从概率上来讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程被执行完以后,低优先级的线程才会被执行。
七、总结
线程开启后不一定立即执行,有CPU进行调度(如果只有一个CPU,主线程和创建的线程会交替执行)
加载全部内容