多线程的主要操作方法都在Thread类中定义的
多线程的运行状态是不确定的,那么在程序的开发之中为了可以获取到一些需要使用到的线程就只能够依靠线程的名字来进行操作。所以线程的名字是一个至关重要的概念,这样在Thread类之中就提供有线程名称的处理
‒ 构造方法:public Thread(Runnable target,String name)
‒ 设置名字:public final void setName(String name)
‒ 取得名字:public final String getName()
对于线程对象的获得是不可能只是依靠一个this来完成的,因为线程的状态不可控,但是有一点是明确的,所有的线程对象一定要执行run()方法,那么这个时候可以考虑获取当前线程,在Thread类里面提供有获取当前线程的方法:
‒ 获取当前线程:public static Thread currentThread()
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
public class MyThread5 implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
MyThread5 mt = new MyThread5();
new Thread(mt,"线程A").start(); // 设置了线程的名字
new Thread(mt).start(); // 未设置线程名字
new Thread(mt,"线程B").start();// 设置了线程的名字
通过此时的代码可以发现当使用了"mt.run()“直接在主方法之中调用线程类对象中的run()方法所获得的线程对象的名字为"main”,所以可以得出结论:主方法也是一个线程。那么现在的问题来了,所有的线程都是在进程上的划分,那么进程在哪里?每当使用java命令执行程序的时候就表示启动了一个JVM的进程,一台电脑上可以同时启动若干个JVM进程,所以每一个JVM的进程都会有各自的线程。
MyThread5 mt = new MyThread5();
new Thread(mt,"线程A").start(); // 设置了线程的名字
new Thread(mt).start(); // 未设置线程名字
new Thread(mt,"线程B").start();// 设置了线程的名字
mt.run();
在任何的开发之中,主线程可以创建若干个子线程,创建子线程的目的是可以将一些复杂逻辑或者比较耗时的逻辑交由子线程处理。
System.out.println("执行操作任务1");
new Thread(()->{
int temp = 0;
for(int x = 0 ; x < Integer.MAX_VALUE;x++){
temp += x ;
}
});
System.out.println("执行操作任务2");
System.out.println("执行操作任务3");
主线程负责处理整体流程,而子线程负责处理耗时操作。
线程休眠
如果说现在希望某一个线程可以暂缓执行一次,那么就可以使用休眠的处理,在Thread中定义的休眠方法如下:
‒ public static void sleep(long millis) throws InterruptedException
‒ public static void sleep(long millis,nt nanos) throws InterruptedException
在进行休眠的时候有可能会产生中断异常"InterruptException",中断异常属于Exception的子类,所以证明该异常必须进行处理。
new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"i="+i);
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
},"线程对象").start();
休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续的处理。但是需要注意的是,如果现在有多个线程对象,那么休眠也是有先后顺序的。
多线程进行休眠:
Runnable run =()->{
for(int x =0 ;x <10;x++){
System.out.println(Thread.currentThread().getName()+"\tx="+x);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
};
for (int i = 0; i < 5; i++) {
new Thread(run,"线程对象 - " + i).start();
}
线程中断
在之前发现线程的休眠里面提供有一个中断异常,实际上就证明线程的休眠是可以被打断的,而这种打断肯定是其他线程完成的,在Thread类里面提供有这种中断执行的处理方法
‒ 判断线程是否被中断:public boolean isInterrupted()
‒ 中断线程执行:public void interrupt()
Thread thread = new Thread(()->{
System.out.println("*******72个小时的疯狂我需要睡觉补充精力");
try{
Thread.sleep(10000); // 预计准备休眠10s
System.out.println("*******睡足了,可以继续出去祸害别人了");
}catch(InterruptedException e){
System.out.println("敢打扰我睡觉,老子x了你");
}
});
thread.start(); // 开始睡
Thread.sleep(1000);
if(!thread.isInterrupted()){
// 该线程中断了么?
System.out.println("我偷偷打扰一下你的睡眠");
thread.interrupt(); // 中断执行
}
所有正在执行的线程都是可以被中断的,中断的线程必须进行异常的处理
。
线程强制运行
所谓的线程强制执行指的是放满足于某些条件之后,某一个线程对象将可以一直独占资源,一直到该线程大的程序执行结束。
‒ 强制执行:public final void join() throws InterruptedException
// 强制进行线程
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(()->{
for (int i = 0; i < 100; i++) {
if (i==3){
try {
mainThread.join();
}catch (InterruptedException e){
e.printStackTrace();
}
}
try {
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行i="+i);
}
},"玩耍的线程");
thread.start();
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
System.out.println("霸道的线程"+Thread.currentThread().getName()+"线程:"+"number="+i);
}
在进行线程强制执行的时候一定要获取强制执行线程对象之后才可以执行join()调用。
线程礼让
线程的礼让指的是先将资源让出去让别的线程先执行。线程的礼让可以使用Thread中提供的方法:
‒ 礼让:public static void yield()
// 线程礼让
Thread thread = new Thread(()->{
for(int x = 0; x <100 ;x ++){
if(x %3 == 0 ){ // 现在霸道线程来了
Thread.yield();// 线程礼让
System.out.println("#####玩耍的线程礼让执行");
}
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +"执行x = " + x);
}
},"玩耍的线程");
thread.start();
for(int x = 0;x<100;x++){
Thread.sleep(100);
System.out.println("霸道的"+Thread.currentThread().getName()+"线程"+"number = "+x);
}
礼让执行的时候每一次调用yield()方法都只会礼让一次当前的资源
线程的优先级
从理论上来讲线程的优先级越高越有可能先执行(越有可能先抢占到资源)。在Thread类里面针对于优先级的操作提供有两个处理方法:
‒ 设置优先级:public final void setPriority(int newPriority)
‒ 获取优先级:public final int getPriority()
在进行优先级定义的时候都是通过int型的数字来完成的,而对于此数字的选择在Thread类里面就定义有三个常量
‒ 最高优先级:public static final int MAX_PRIORITY:10
‒ 中等优先级:public static final int NORM_PRIORITY:5
‒ 最低优先级:public static final int MIN_PRIORITY:1
Runnable run = ()->{
for(int x = 0 ;x < 10 ;x++){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
} System.out.println(Thread.currentThread().getName() + "执行");
}
};
Thread threadA = new Thread(run,"线程对象A");
Thread threadB = new Thread(run,"线程对象B");
Thread threadC = new Thread(run,"线程对象C");
threadA.setPriority(Thread.MIN_PRIORITY);
threadB.setPriority(Thread.MIN_PRIORITY);
threadC.setPriority(Thread.MAX_PRIORITY);
threadA.start();
threadB.start();
threadC.start();
主线程和默认线程属于中等优先级,优先级高的有可能先执行而不是绝对先执行。