线程常用操作方法
多线程主要操作方法都在Thread类中定义。
线程的命名和取得
多线程的运行状态是不确定的,在程序开发中为了可以渠道一些需要使用的线程,就需要线程的名字来进行操作,所以线程的名字是一个至关重要的概念,在Thread类中提供有线程名称的处理。
- 构造方法:public Thread(Runnable target, String name);
- 设置名字:public final void setName(String name);
- 取得名字:public final getName();
对于线程对象的获得是不可能只依靠一个this来完成的,因为线程的状态不可控,但是有一点是明确的,所有的线程对象都要执行run()方法,此时可以考虑获取当前线程,在Thread类中提供有获取当前线程的方法。
- 获取当前线程:public static Thread currentThread();
class Mythread implements Runnable{
public void run{
print(Thread.currentThread().getName())
}
}
class main{
main{
Mythread mt = new Mythread();
new Thread(mt, "线程A").start();
}
}
开发者为线程设置名字时使用设置的名字,未设置时自动生成一个不重复的名字,这种自动的属性命名主要是依靠了static属性完成的。
class Mythread implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
public class ThreadDemo{
public static void main(String args[]){
Mythread mt = new Mythread();
new Thread(mt, "线程对象").start();
mt.run(); //直接调用run()方法
}
}
通过上述代码发现当使用’mt.run()‘直接在主方法之中调用线程类对象中的run()方法,所获的对象名称为’main’,结论:“主方法也是一个线程。”
问题:所有的线程都是在进程之上的划分,那么进程在哪里?
每当使用java命令执行程序的时候就表示启动了一个JVM进程,一台电脑上可以同时启动若干个JVM进程,所有每个JVM进程都会有各自的线程。
在任何开发中,主线程可以创建若干个子线程。创建子线程的目的是可以将一些复杂逻辑或者比较耗时的逻辑交由线程处理。
public class ThreadDemo {
public static void main(String[] args) throws Exception{
System.out.println("1 操作任务1");
//lambda写法
new Thread(()-> {
int temp = 0;
for (int x=0; x <10; x++) {
temp += x;
}
}).start();
System.out.println("2 操作任务2");
System.out.println("3 操作任务3");
}
}
主线程负责处理整体流程,而子线程复杂处理耗时操作。
线程休眠(Thread.sleep())
如果现在希望某一个线程可以暂缓执行一次,就可以使用休眠的处理(Thread类):
- 休眠:public static void sleep(long millis) throws InterruptedException;
- 休眠:public static void sleep(long millis,int nanos) throws InterruptedException;
在进行休眠时可能产生中断异常"InterruptedException",属于Exception子类,所以证明该异常必须处理。
public class ThreadDemo {
public static void main(String[] args) throws Exception{
//lambda写法
new Thread(()-> {
for (int x=0; x <10; x++) {
System.out.println(Thread.currentThread().getName() + ",x=" + x);
try {
Thread.sleep(100); //休眠100毫秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "线程对象").start();
}
}
休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续的处理。但注意如果现在有多个线程对象,休眠以及唤醒也是有先后顺序的。
public class ThreadDemo {
public static void main(String[] args) throws Exception{
for(int num=0;num<5;num++) {
//lambda写法
new Thread(()-> {
for (int x=0; x <10; x++) {
System.out.println(Thread.currentThread().getName() + ",x=" + x);
try {
Thread.sleep(200); //休眠100毫秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "线程对象-" + num).start();
}
}
}
此时将产生五个线程对象,并且这五个线程对象执行的方法体是相同的。此时实际上并非同步休眠和唤醒,中间有先后顺序。
线程中断(Thread.interrupt())
线程的休眠中提供有一个中断异常,实际上证明线程的休眠是可以被打断的,而这种打断是由其他线程完成的。在Thread类中提供有中断执行的处理方法:
- 判断线程是否被中断:public boolean isInterrupted();
- 中断线程执行:public void interrupt();
public class ThreadDemo {
public static void main(String[] args) throws Exception{
Thread thread = new Thread(()->{
System.out.println("******开始睡觉******");
try {
Thread.sleep(10000); //休眠10s
System.out.println("******睡好了******");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("*****扰人清梦*****");
}
});
thread.start();
thread.sleep(1000);
if(!thread.isInterrupted()) {
//判断线程是否中断
System.out.println("****被中断*****");
thread.interrupt(); //中断执行
}
}
}
所有正在执行的线程都是可以被中断的,中断线程必须进程异常处理。
线程强制运行
强制执行指的是满足某些条件之后,某一线程对象将可以独占资源,一直到该线程的程序执行结束。
public class ThreadDemo {
public static void main(String[] args) throws Exception{
Thread thread = new Thread(()->{
for(int x = 0; x<100;x++) {
System.out.println(Thread.currentThread().getName() + "执行、x="+ x);
}
},"玩耍的线程");
thread.start();
for(int x =0;x<50;x++) {
System.out.println("main线程=" +x );
}
}
}
此时主线程和子线程都在交替执行着,但是如果希望主线程独占执行,则可以利用Thread中的方法强制执行:
- 强制执行:public final void join() throws InterruptedException;
public class ThreadDemo {
public static void main(String[] args) throws Exception{
Thread mainThread = Thread.currentThread(); //获得主线程
Thread thread = new Thread(()->{
for(int x = 0; x<100;x++) {
if(x==3) {
try {
mainThread.join(); //主线程要先执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行、x="+ x);
}
},"玩耍的线程");
thread.start();
for(int x =0;x<50;x++) {
System.out.println("main线程=" +x );
}
}
}
在线程强制执行的时候一定要获取强制执行线程对象之后才可以执行join()的调用。
线程礼让
线程礼让指的是先将资源让出去让别的线程先执行,线程的礼让可以使用Thread提供的方法:
- 线程礼让:public static void yield();
public class ThreadDemo {
public static void main(String[] args) throws Exception{
Thread thread = new Thread(()->{
for(int x = 0; x<50;x++) {
if(x %3 ==0) {
Thread.yield(); //礼让执行
}
System.out.println(Thread.currentThread().getName() + "执行、x="+ x);
}
},"玩耍的线程");
thread.start();
for(int x =0;x<50;x++) {
System.out.println("main线程=" +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;
public class ThreadDemo {
public static void main(String[] args) throws Exception{
Runnable run = ()->{
for(int x=0; x< 10; x++) {
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();
}
}
主方法是一个主线程,主线程的优先级为中等优先级(5);默认创建的线程也是中等优先级。