1 线程命名的取得
多线程的主要操作方法都在Thread类中定义的。
首先多线程的运行状态是不确定的,那么在程序的开发之中为了可以获取到一些需要使用到的线程就只能依靠线程的名字来进行操作。所以线程的名字是一个至关重要的概念,这样在Thread类之中就提供有线程名称的处理。
(1)构造方法:public Thread(Runnable target, String name);
(2)设置名字:public final void setName(String name);
(3)取得名字:public final String getName();
对于线程对象的获得是不可能只是依靠一个this来完成的,因为线程的状态不可控,但是有一点是明确的,所有的线程对象一定要执行run()方法,那么这个时候可以考虑获取当前线程,在Thread类里面提供有获取当前线程的方法。
(1)获取当前线程:public static Thread currentThread()
范例:观察线程的命名操作
class MyThread implements Runnable{
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "run: i = " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] main)throws Exception {
new Thread(new MyThread(), "Thread-A").start();
new Thread(new MyThread()).start();
new Thread(new MyThread(), "Thread-B").start();
}
}
当开发者为线程设置名字的时候就使用设置的名字,而如果没有设置名字,则会自动生成一个不重复的名字。这种自动的属性命名主要是依靠了static属性完成的,在Thread类里面定义了有如下操作:
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
范例:观察一个程序
public class ThreadDemo {
public static void main(String[] main)throws Exception {
new Thread(new MyThread(), "Thread-A").start();
new Thread(new MyThread()).start();
new Thread(new MyThread(), "Thread-B").start();
System.out.println(Thread.currentThread().getName());
}
}
通过此时代码可以发现当使用了“thread.run()”直接在主方法之中调用线程类对象中的run()方法所获得的线程对象的名字为"main",所以可以得出一个结论:主方法也是一个线程。那么现在问题来了,所有的线程都是在进程上的划分,那么进程在哪里?每当使用java命令执行程序的时候就表示启动了一个JVM的进程,一台电脑上可以同时启动若干个JVM进程,所以每个JVM进程都会有各自的线程。
在任何的开发之中,主线程可以创建若干个子线程,创建子线程的目的是可以将一些复杂逻辑或者比较耗时的逻辑交由子线程处理;
范例:子线程处理
public class ThreadDemo {
public static void main(String[] main)throws Exception {
System.out.println("**********[主程序启动]*********");
new Thread(()->{
for(int i = 0; i < 100; i++)
System.out.println("**********[子程序1启动执行]*********");
}).start() ;
System.out.println("**********[主程序执行]*********");
System.out.println("***********[Over]***********");
}
}
主线程负责处理整体流程,而子线程负责处理耗时操作。
2 线程休眠
如果说现在希望某一个线程暂缓执行,那么就可以使用休眠的处理,在Thread类之中定义的休眠方法如下:
(1)休眠:public static void sleep(long millis) throws InterruptedException;
(2)休眠:public static void sleep(long millis, int nanos) throws InterruptedException;
在进行休眠的时候有可能会产生中断异常“InterruptedException”,中断异常属于Exception子类,所以证明该异常必须进行处理。
范例:观察休眠处理
package cn.victor.demo;
class MyThread implements Runnable{
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "run: i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ThreadDemo {
public static void main(String[] main)throws Exception {
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
}
}
休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续的处理。但是需要注意的是,如果现在你有多个线程对象,那么休眠也是有先后顺序的。
范例:产生多个线程对象进行休眠处理
package cn.victor.demo;
class MyThread implements Runnable{
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "run: i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ThreadDemo {
public static void main(String[] main)throws Exception {
for(int i =0; i < 5; i++) {
new Thread(()->{
for(int j =0; j < 100; j++) {
System.out.println(Thread.currentThread().getName() + "Thread run " + j);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start() ;
}
}
}
此时将产生五个线程对象,并且这五个线程对象执行的方法体是相同的。此时从程序执行的感觉上来讲好像是若干个线程一起进行了休眠,而后一起进行了唤醒,但是实际上是有差别的。
3 线程中断
在之前发现线程的休眠里面提供有一个中断异常,实际上就证明线程的休眠是可以被打断的,而这种打断肯定是由其它线程完成的,在Thread类里面提供有这种中断执行的处理方法:
(1)判断线程是否被中断:public boolean isInterrupted()
;
(2)中断线程执行:public void interrupt()`;
范例:观察线程的中断处理操作
public static void main(String[] main)throws Exception {
Thread th = new Thread() {
@Override
public void run() {
System.out.println("海燕学习太累了,休息会");
try {
Thread.sleep(10000);
System.out.println("海燕休息好了,继续学习");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("恶龙咆哮,嗷呜嗷呜!");
}
}
} ;
th.start();
Thread.sleep(2000);
if(!th.isInterrupted()) {
System.out.println("当头一摸");
th.interrupt();
}
}
所有正在执行的线程都是可以被中断的 ,中断线程必须进行异常的处理。
4 线程强制运行
所谓的线程强制执行指的是当满足于某些条件之后,某一个线程对象将可以一直独占资源,一直到该线程的程序执行结束。
范例:观察一个没有强制执行的程序
public static void main(String[] main)throws Exception {
Thread th = Thread.currentThread();
new Thread(()->{
for(int i = 0; i < 100; i++) {
System.out.println("小屁孩玩泥巴!");
}
}, "小屁孩进程").start();
for(int i =0; i < 100; i++) {
System.out.println("大人建房子!");
}
}
这个时候主线程和子线程都在交替执行,一直到执行完毕,但是如果现在希望主线程独占执行。那么就可以利用Thread类中的方法。
(1)强制执行:public final void join() throws InterruptedException;
范例:多线程的强制执行
public static void main(String[] main)throws Exception {
Thread th = Thread.currentThread();
new Thread(()->{
for(int i = 0; i < 100; i++) {
if(i == 10) {
try {
th.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("小屁孩玩泥巴!");
}
}, "小屁孩进程").start();
for(int i =0; i < 100; i++) {
System.out.println("大人建房子!");
}
}
在进行线程强制执行的时候一定要获取强制执行线程对象之后才可以执行join的调用。
5 线程礼让
线程的礼让指的是先将资源让出去让别的线程先执行。线程的礼让可以使用Thread中提供的方法:
(1)礼让:public static void yield();
范例:使用礼让操作
public static void main(String[] main)throws Exception {
new Thread(()->{
for(int i = 0; i < 100; i++) {
if(i% 3 == 0) {
System.out.println(Thread.currentThread().getName() + "yield!");
Thread.currentThread().yield();
}
System.out.println("小屁孩玩泥巴!");
}
}, "小屁孩进程").start();
new Thread(()->{
for(int i =0; i < 100; i++) {
System.out.println("大人建房子!");
}
}, "大屁孩进程").start();
}
礼让执行的时候每一次调用yield()方法都只会礼让一次当前的资源。
6 线程优先级
从理论上来讲线程的优先级越高越有可能先执行(越有可能先抢占到资源)。在Thread类里面针对优先级的操作提供有如下的两个处理方法:
(1)设置优先级:public final void setPriority(int newPriority);
(2)获取优先级:public final int getPriority();
在进行优先级定义的时候都是通过int型的数字来完成的,而对于此数字的选择在Thread类里面就定义有三个常量:
(1)最高优先级:public static final int MAX_PRIORITY;
(2)中等优先级:public static final int NORM_PRIORITY;
(3)最低优先级:public static final int MIN_PRIORITY;
范例:观察优先级
class MyThread implements Runnable{
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "run: i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ThreadDemo {
public static void main(String[] main)throws Exception {
Runnable mt = new MyThread();
Thread threadA = new Thread(mt);
Thread threadB = new Thread(mt);
Thread threadC = new Thread(mt);
threadA.setPriority(Thread.MAX_PRIORITY);
threadB.setPriority(Thread.MIN_PRIORITY);
threadC.setPriority(Thread.MIN_PRIORITY);
threadA.start();
threadB.start();
threadC.start();
}
}
主方法是一个主线程,那么主线程的优先级呢?
public class ThreadDemo {
public static void main(String[] main)throws Exception {
Thread th = Thread.currentThread();
Runnable mt = new MyThread();
Thread threadA = new Thread(mt);
System.out.println(threadA.getPriority());
System.out.println(th.getPriority());
}
}
主线程属于中等优先级,而默认创建的线程也是中等优先级。