线程:是操作系统能够进行运算调度的最小单位。它被包含在进程中,是进程中实际运作单位
进程:进程是程序的基本执行实体,一个程序就是一个进程
简单理解线程:
应用软件中相互独立,可以同时运行的功能
有了多线程,就可以让程序同时做多件事
线程的生命周期
完整的线程状态
New(新建状态) ->创建线程对象
至今尚未启动的线程处于这种状态
RUNNABLE(就绪状态) ->start方法
在Java虚拟机中执行的线程处于此状态
BLOCKER(阻塞状态) ->无法获得锁对象
被阻塞等待监视器锁定的线程处于此状态
WAITING(等待状态) ->wait方法
无限期的等待另一个线程执行特定动作的线程处于此状态
TIMED_WAITING(计时状态) ->sleep方法
正在等待另一个线程执行动作达到指定等待时间的线程处
TERMINATED(结束状态) ->全部代码运行完毕
已退出的线程处于此状态
多线程的实现方式
1.继承Thread类的方式进行实现
2.实现Runnable接口的方式进行实现
3.利用Callable接口和Future接口方式实现
多线程的第一种启动方式
1.自己定义一个类继承Thread
2,重写run方法
3.创建子类的对象,并启动线程
例如
public class MyThread extends Thread{
@Override
public void run(){
//书写线程要执行代码
for(int i=0; i<100; i++){
System.out.println(getName()+"HelloWord");
}
}
}
public class MyThreadTest{
public static void main(String[] args){
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
多线程的第二种启动方式
1.定义一个类实现Runnable接口
2.重写里面的run方法
3.创建自己类的对象
4.创建一个Thread类的对象,并开启线程
例如
public class MyRun implements Runnable{
@Override
public void run(){
for(int i=0; i<100; i++){
//获取到当前的对象
//Thread t=Thread.currentThread();
//System.out.println(t.getName()+"HelloWorld")
System.out.println(Tread.currentThread.getName()+"HelloWorld");
}
}
}
public class MyRunnableTest{
public static void main(String[] args){
//创建MyRun的对象
//表示多线程要执行的任务
MyRun mr=new MyRun();
//创建线程对象
Thread t1=new Thread(mr);
Thread t2=new Thread(mr);
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
}
}
多线程的第三种实现方式
特点:可以获取到多线程运行的结果
1.创建一个类MyCallable实现Callable接口
2.重写call(是有返回值的,表示多线程运行的结果)
例如
public class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception{
//1~100之间的和
int sum=0;
for(int i =0; i<100;i++){
sum+=i;
}
return sum;
}
}
3.创建MyCallable的对象(表示多线程要执行的任务)
4.创建FutureTask的对象(作用管理多线程运行的结果)
5.创建Thread类的对象,并启动(表示线程)
public class ThreadDemo{
public static void main(String[] args) throws ExcutionException{
//创建MyCallable的对象(表示多线程要执行的任务)
MyCallable mc =new MyCallable();
//创建FuturnTask的对象(作用管理多线程运行的结果)
FutureTask<Integer> ft =new FutureTask<>(mc);
//创建线程的对象
Thread t1 =new Thread(ft);
//启动线程
t1.start();
//获取多线程运行的结果
Integer result =ft.get();
System.out.println(result);
}
}
多线程三种实现方式对比
继承Thread类:
优点:编程比较简单,可以直接使用Thread类中的方法
缺点:扩展性较差,不能再继承其他的类
实现Runnable接口
优点:扩展性强,实现该接口的同时还可以继承其他的类
缺点:编程相对复杂,不能直接使用Thread类中方法
实现Callable接口
优点:
1.可以获取到多线程的运行的结果
2.扩展性强,实现该接口的同时还可以继承其他的类
确定:编程相对复杂,不能直接使用Thread类中的方法
Thread常见的成员方法
方法名称 | 说明 |
---|---|
String getName() | 返回此线程的名称 |
void setName(String name) | 设置线程的名字(构造方法也可以设置名字) |
static Thread currentThread() | 获取当前线程的对象 |
static void sleep(long time) | 让线程休眠指定的时间,单位为毫秒 |
setPriority(int new Priority) | 设置线程的优先级 |
final int getPriority() | 获取线程的优先级 |
final void setDaemon(boolean on) | 设置为守护线程 |
public static void yield() | 出让线程/礼让线程 |
public static void join() | 插入线程/插队线程 |
方法名称 | 说明 |
---|---|
String getName() | 返回此线程的名称 |
void setName(String name) | 设置线程的名字(构造方法也可以设置名字) |
细节:
1.如果我们没有给线程设置名字,线程也是有默认的名字的
格式:Thread-X(X为序号,从0开始)
2.如果我们要给线程设置名字,可以用set方法进行设置,也可以用构造方法进行设置
注意:子类要使用父类的有参构造器,要先生成有参构造器
方法名称 | 说明 |
---|---|
More Actions static Thread currentThread() | 获取当前线程的对象 |
细节:
当JVM虚拟机启动之后,会自动的启动多条线程
其中有一天线程就叫做main线程,作用就是调用main方法并执行里面的代码
在以前,我们写的所有代码,其实都运行在main线程当中
方法名称 | 说明 |
---|---|
static void sleep(long time) | 让线程休眠指定的时间,单位为毫秒 |
细节:
1.哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
2.方法的参数:就表示睡眠的时间,单位毫秒 1秒=1000毫秒
3.当时间到了之后,线程会自动的醒来,继续执行下面的其他代码
方法名称 | 说明 |
---|---|
setPriority(int new Priority) | 设置线程的优先级 |
final int getPriority() | 获取线程的优先级 |
细节:Java是抢占式调度,体现了随机性
多个线程抢夺cpu的执行权,cpu在什么时候执行哪条线程是不确定的,执行多长时间也是不确定的
没有设置线程的优先级,默认为5,最小权重为1,最大权重为10
权重越大随机到的概率越大,但不是100%
方法名称 | 说明 |
---|---|
final void setDaemon(boolean on) | 设置为守护线程 |
细节:当其他的非守护线程执行完毕之后,守护线程会陆续结束
简单来说:当女神线程结束了,那么备胎也就没有存在的必要了
public class MyThread1 extends Thread{
@Override
public void run(){
for(int i=1;i<=10;i++){
System.out.println(getName()+"@"+i);
}
}
}
public class MyThread2 extends Thread{
@Override
public void run(){
for(int i=1; i<=100; i++){
System.out.println(getName()+"@"+i);
}
}
}
public class ThreadDemo{
public static void main(String[] args){
MyThread t1 =new MyThread1();
MyThread t2 =new MyThread2();
t1.setName("女神");
t2.setName("备胎");
//把第二个线程设置为守护线程(备胎线程)
t2.setDaemon(true);
t1.start();
t2.start();
//女神运行10次时,备胎就会停止运行,不会执行到100次
}
}
守护线程应用场景
例如:聊天和传输文件,聊天是一个线程,传输文件也是一个线程
当聊天关闭,那么传输文件也应该关闭,可以把传输文件设置为守护线程
方法名称 | 说明 |
---|---|
public static void yield() | 出让线程/礼让线程 |
作用:为了让结果分布更加均匀,但不是绝对
举例
public class MyThread extends Thread{
@Override
public void run(){
for(int i=1; i<=100;i++){
System.out.println(getName()+"@"+i);
//表示出让当前CPU的执行权
//线程会重新抢夺CPU的执行权
Thread.yield();
}
}
}
public class ThreadDemo{
public static void main(String[] args){
MyThread t1 = new Thread();
MyThread t2 = new Thread();
t1.setName("飞机");
t2.setName("坦克");
t1.start();
t2.start();
}
}
方法名称 | 说明 |
---|---|
public static void join() | 插入线程/插队线程 |
举例
public class MyThread extends Thread{
@Override
public void run(){
for(int i = 1; i<=100; i++){
System.out.println(getName()+"@"+i);
}
}
}
public class ThreadDemo{
public static void main(String[] args){
MyThread t = new MyThread();
t.setName("土豆");
t.start();
//表示把t这个线程插入当前线程之前
//t:土豆
//当前线程:main线程
//土豆线程执行完才执行main线程
t.join();
//执行在main线程当中的
for(int i = 0; i<10; i++){
System.out.println("main线程"+i);
}
}
}
标签:Thread,int,void,介绍,线程,简单,多线程,public
From: https://www.cnblogs.com/zhao-zong-yu-hai/p/17990766