线程的创建和启动方式一
- 创建一个继承于Thread类的子类
- 重写Thread类的run():将此线程执行的操作写在run()中
- 创建Thread类的子类对象
- 通过此对象调用start()
①启动当前线程
②调用当前线程的run()
- 例子:遍历10000以内的所有偶数
public class ThreadTest {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
//启动线程
thread1.start();
//主线程
for(int i = 0;i <= 100;i++) {
if (i % 2 == 0)
System.out.println(i + "*********main*********");
}
}
}
class MyThread extends Thread{
@Override
public void run() {
super.run();
for(int i = 0;i <= 10000;i++){
if(i % 2 == 0)
System.out.println(i);
}
}
}
- 创建线程的简便方式
//创建Thread类的匿名子类方式
new Thread(){
@Override
public void run() {
super.run();
for(int i = 0;i <= 100;i++){
if(i % 2 == 0)
System.out.println(i + "thread1");
}
}
}.start();
- 问题一:不能通过对象直接调用run()来启动线程,必须要用对象的start()。
- 问题二:再启动一个线程,不可以让已经start()的对象去启动,要再创建一个对象,然后让他start()
线程的常用方法
start()
:启动当前线程,调用当前线程的run();
run()
:通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
currentThread()
:静态方法,返回当前代码的线程
getName()
:获取当前线程的名字
setName()
:设置当前线程的名字
yield()
:释放当前CPU执行权,让当前线程失去CPU
join()
:在线程a中调用线程b的join()方法,此时线程a进入阻塞状态,直到线程b执行完以后,线程a才结束阻塞状态。
sleep(long millitime)
:让当前线程阻塞millitime
毫秒
isAlive()
:判断当前线程是否存活
线程的调度
-
线程的优先级
MAX_PRIORITY = 10
NORM_PRIORITY = 5
:默认的优先级
MIN_PRIORITY = 1
-
获取和设置当前线程的优先级
getPriority()
setPriority(int p)
说明:高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。
创建线程的方式二:实现Runnable
接口
- 创建一个实现了
Runnable
接口的类 - 实现类去实现
Runnable
中的抽象方法:run() - 创建实现类的对象
- 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
- 通过Thread类的对象调用start()
public class ThreadTest1 {
public static void main(String[] args) {
MThread thread1 = new MThread();
Thread t1 = new Thread(thread1);
MThread thread2 = new MThread();
Thread t2 = new Thread(thread2);
t1.start();
t2.start();
}
}
class MThread implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 100;i++){
if(i % 2 == 0)
System.out.println(Thread.currentThread().getName() + "*********" + i);
}
}
}
比较创建线程的两种方式
-
开发中,优先选择实现Runnable的方式,
原因:
1、实现的方式没有类的单继承性的局限性
2、实现的方式更适合来处理多个线程有共享数据的情况 -
二者联系
public class Thread implements Runnable
Thread类也实现了Runnable接口 -
相同点
都需要重写run(),将线程要执行的逻辑声明在run()中
线程的生命周期
image.png线程的同步
- 当一个线程a在操作共享数据的时候,其他线程不能参与进来,直到线程a操作完共享数据,其他线程才能操作共享数据
- 方式一 synchronize
synchronize(同步监视器){
//需要被同步的代码
}
说明:
1、操作共享数据的代码,即为需要被同步的代码 不能包多也不能包少
2、同步监视器,俗称:锁。任何一个类的对象都可以充当锁
要求多个线程必须拥有同一把锁
补充:
在实现Runnable接口创建多线程的方式中,我们还可以考虑使用this充当同步监视器
在继承Thread类创建多线程的方式中,慎用this充当同步监视器。可以考虑使用当前类充当同步监视器。
- 方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
总结:
1、同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
2、非静态的同步方法,同步监视器是this
3、静态的同步方法,同步监视器是当前类本身
网友评论