一、前言
多线程的主要操作方法都在Thread中定义的。
二、线程的命名与取得
多线程的运行状态是不确定的,那么在程序的开发过程中为了可以获取需要使用到的线程只能依靠名字来进行操作,所以线程的名字是至关重要的。
1.构造方法:public Thread(Runnable target, String name);
2.设置名字:public final void setName(String name);
3.取得名字:public final String getName();
获取线程对象不可能只依靠一个this来完成的,因为线程的状态不可控,但是线程一定会执行run()方法,这时候可以考虑获取当前的线程对象,Thread提供了获取当前线程对象的方法。
public static Thread currentThread();
范例:观察线程的命名操作
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Main {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"线程A").start();
new Thread(mt).start();
new Thread(mt,"线程B").start();
}
}
运行结果:
如果线程没有设置名字,则会自动生成不重复的名字,这种自动的属性命名主要依靠于static实现的,在Thread定义了如下操作:
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
范例:观察一个实例
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Main {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"线程A").start();
mt.run();
}
}
运行结果:
说明了当直接调用线程对象的run()方法时,运行结果是main,说明主方法也是一个线程。
问题:进程在哪里?
每当使用java命令执行程序的时候就表示启动了一个JVM的进程,一台电脑上可以启动若干个JVM进程,JVM进程都有自己的线程。
子线程和主线程:
在任何开发过程中,主线程可以创建若干个子线程,创建子线程的目的主要是将一些复杂逻辑或者比较耗时的逻辑交由子线程处理。主线程负责整体的流程控制。子线程负责处理耗时操作。
范例:子线程负责统计
public class Demo {
public static void main(String[] args) {
System.out.println("操作任务一");
new Thread(()->{ //子线程负责统计
int temp = 0;
for(int i = 0; i< Integer.MAX_VALUE; i++){
temp += i;
}
});
System.out.println("操作任务二");
System.out.println("操作任务n");
}
}
三、线程的休眠
如果希望一个线程可以暂缓执行,那么可以使用休眠的操作,在Thread中定义的休眠方法有:
1. public static native void sleep(long millis) throws InterruptedException;
2. public static void sleep(long millis, int nanos) throws InterruptedException;
进程休眠的时候可能会产生中断异常:“InterruptedException” ,此异常为“Exception”的子类,说明该异常必须进行处理。
范例:观察休眠处理
public class SleepDemo {
public static void main(String args[]){
new Thread(()->{
for(int i = 0; i < 10; i++ ){
System.out.println(Thread.currentThread().getName()+",i="+i);
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
},"线程对象").start();
}
}
休眠的主要特点是可以自动进行线程的唤醒,以继续后面的处理。如果有多个线程对象,那么休眠也是有先后顺序的
范例:多个线程休眠
public class SleepDemo {
public static void main(String args[]){
for (int j = 0; j< 5; j++) {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ",i=" + i);
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}, "线程对象"+j).start();
}
}
}
多个线程并不是同时执行,中间有适当的延迟操作。
四、线程中断
线程休眠抛出中断异常,线程的休眠是可以被打断的,而这种操作是其他线程完成的,在Thread中提供了中断执行的处理方法。
1.判断线程是否被中断:public boolean isInterrupted();
2.中断线程执行:public void interrupt();
范例:观察线程的中断处理操作
public class ThreadDemo {
public static void main(String args[]){
Thread thread = new Thread(()->{
System.out.println("休息一下。。。");
try {
Thread.sleep(10000);
System.out.println("我回来了");
} catch (InterruptedException e) {
System.out.println("敢打扰我的睡眠,不想活了吗");
}
});
thread.start();
try {
thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!thread.isInterrupted()){
System.out.println("打扰一下");
thread.interrupt();
}
}
}
运行结果:
五、线程的强制执行
所谓的线程的强制执行就是当满足某些条件之后,某一个线程对象将可以一直占用资源,一直到线程结束。
范例:观察一个没有强制执行的程序
public class ThreadDemo1 {
public static void main(String[] args) {
Thread thread = new Thread(()->{
for(int i = 0; i<100; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+",i="+i);
}
},"子线程");
thread.start();
for(int i = 0; i< 100; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【主线程main】 number="+i);
}
}
}
结论:主线程和子线程竞争抢资源。
如果希望主线程一直独占执行,那么可以利用Thread中的方法。
强制执行:public final void join() throws InterruptedException;
范例:强制主进程先执行
public class ThreadDemo1 {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(()->{
for(int i = 0; i<100; i++){
if(i == 5){
try {
mainThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+",i="+i);
}
},"子线程");
thread.start();
for(int i = 0; i< 100; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【主线程main】 number="+i);
}
}
}
六、线程礼让
线程礼让就是让出资源让别的进程先执行,Thread中有相关礼让的方法:
礼让:public static void yield();
范例:使用礼让执行
public class ThreadDemo1 {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(()->{
for(int i = 0; i<100; i++){
if(i % 3 ==0){
Thread.yield();
System.out.println("子线程礼让执行");
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+",i="+i);
}
},"子线程");
thread.start();
for(int i = 0; i< 100; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【主线程main】 number="+i);
}
}
}
调用了yield()只礼让一次当前的资源。
七、线程优先级
从理论上讲:线程优先级越高约有可能先执行(也有可能先抢到资源),在Thread中提供了相关方法:
设置优先级:public final void setPriority(int newPriority);
获取优先级:public final int getPriority();
定义优先级都是通过int型的数字来表示的,而对于此数字的选择在Thread中就定义了
最高优先级:public static final int MAX_PRIORITY=10;
默认优先级:public final static int NORM_PRIORITY = 5;
最小优先级: public final static int MIN_PRIORITY = 1;
范例:观察优先级
public class ThreadDemo2 {
public static void main(String[] args) {
Runnable run = ()->{
for(int i = 0; i< 10; i++){
System.out.println(Thread.currentThread().getName()+" i ="+i);
}
};
Thread thread1 = new Thread(run,"线程A");
Thread thread2 = new Thread(run,"线程B");
Thread thread3 = new Thread(run,"线程C");
thread3.setPriority(Thread.MAX_PRIORITY);
thread1.start();
thread2.start();
thread3.start();
}
}
主线程的优先级为5,属于中等优先级。默认线程也是中等优先级。