Java多线程常用的几种方法
1.线程的命名和取得
多线程的主要操作方法都在Thread类中定义
多线程的运行状态是不确定的, 那么在程序的开发之中为了可以获取到一些需要使用的线程就只能偶依靠线程的名字来进行操作。所以线程的名字是一个至关重要的概念,这样在Thread类中就提供有线程名称的处理
构造方法:
Thread(Runnable target, String name)
设置名字:
void
setName(String name)
改变线程名称,使之与参数 name 相同。
获取名字:
String
getName()
对于线程对象的获得是不可能只依靠一个this来完成的, 因为线程的状态不可控, 但是有一点是明确的, 所有的线程对象一定要执行run方法,那么这个时候,可以考虑获取当前线程, 在Thread类里面提供有获取当前线程的方法
获取当前线程的方法:
static Thread
currentThread()
返回对当前正在执行的线程对象的引用。
当开发者为线程设置名字的时候就使用设置的名字, 而如果没有设置名字, 则会自动生成一个不重复的名字
范例:
观察线程的命名操作:
import java.util.*;
class MyThread1 implements Runnable{ //线程的主体类
private int ticket = 5;
private String title;
public MyThread1()
{
this.title = title;
}
public void run(){ //线程创建的主体方法
System.out.println(Thread.currentThread().getName());
}
}
public class Thread1 {
public static void main(String [] args)
{
// Thread mt1 = new Thread(new MyThread(), "n");
MyThread1 mt = new MyThread1();
Thread m1 = new Thread(mt, "mt1");
Thread m2 = new Thread(mt);
Thread m3 = new Thread(mt, "mt3");
m1.start();
m2.start();
m3.start();
}
}
如果设置了名字, 就会使用设置的名字, 如果没有设置名字会自动命名, 这种自动的属性命名主要是依靠了static属性完成的, 在Thread中,定义有如下操作:
观察一个程序:
import java.util.*;
class MyThread1 implements Runnable{ //线程的主体类
private int ticket = 5;
private String title;
public MyThread1()
{
this.title = title;
}
public void run(){ //线程创建的主体方法
System.out.println(Thread.currentThread().getName());
}
}
public class Thread1 {
public static void main(String [] args)
{
// Thread mt1 = new Thread(new MyThread(), "n");
MyThread1 mt = new MyThread1();
Thread m1 = new Thread(mt, "线程对象");
mt.run();
/* Thread m2 = new Thread(mt);
Thread m3 = new Thread(mt, "mt3");
m1.start();
m2.start();
m3.start();*/
}
}
也就是说直接在main方法里直接调用线程类对象中的run()方法所获得的线程对象的名字为"main", 所以可以得出结论:主方法也是线程, 那么进程在哪里
2.线程休眠
1.如果说现在希望某一线程可以暂缓执行, 那么久可以使用休眠的处理, 在Thread类中定义的休眠的方法如下:
- public static void sleep(long millis) throws InterruptedException
2.public static void sleep(long millis,int nanos) throws InterruptedException
2.在进行休眠的时候, 有可能会产生中断异常 InterruptedException, 中断异常属于Exception的子类, 说明该异常必须被处理
import java.lang.Thread;
public class ThreadDemo {
public static void main(String [] args) throws Exception{
new Thread(()->{
for(int x = 0; x<10; x++){
System.out.println(Thread.currentThread().getName() + "x= " + x);
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }, "线程对象").start(); }
}
3.休眠的主要特点是可以自动实现线程的唤醒, 以继续进行后续的处理, 但是需要注意的是, 如果你有多个线程对象, 那么, 休眠也是有先后顺序的
4.产生线程对象进行休眠处理
import java.lang.Thread;
public class ThreadDemo {
public static void main(String [] args) throws Exception{
for(int num=0; num<3; num++)
{
new Thread(()->{
for(int x = 0; x<10; x++){
System.out.println(Thread.currentThread().getName() + "x= " + x);
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }, "线程对象" + num).start(); } }
}
执行结果:
线程对象0x= 0
线程对象1x= 0
线程对象2x= 0
线程对象0x= 1
线程对象1x= 1
线程对象2x= 1
线程对象0x= 2
线程对象2x= 2
线程对象1x= 2
线程对象0x= 3
线程对象2x= 3
线程对象1x= 3
线程对象1x= 4
线程对象2x= 4
线程对象0x= 4
线程对象2x= 5
线程对象0x= 5
线程对象1x= 5
线程对象2x= 6
线程对象0x= 6
线程对象1x= 6
线程对象0x= 7
线程对象2x= 7
线程对象1x= 7
线程对象1x= 8
线程对象0x= 8
线程对象2x= 8
线程对象1x= 9
线程对象2x= 9
线程对象0x= 9
5.这里将产生3个线程对象, 并且每个线程对象的方法体是相同的, 此时从程序执行的感觉上来讲, 好像是若干个线程一起进行休眠, 而后一起进行了自动唤醒, 但是实际上是有差别的。
3.线程中断
1.在之前的线程休眠里面就有一个中断异常, 实际上就证明线程的休眠是可以被打断的, 而这种打断肯定是其他线程完成的
2.在Thread类里面提供有这种中断执行的处理方法:
判断线程是否被中断:
boolean isInterrupted() 测试线程是否已经中断
中断线程的执行: public void interrupt() 中断线程。
3.观察线程的终端处理:
Thread m1 = new Thread(()->{
System.out.println("72个小时的疯狂, 我需要补充精力");
try { // System.out.println("开始睡觉了没"); Thread.sleep(10000); System.out.println("*** 睡足了, 可以出去继续祸害别人了."); } catch (InterruptedException e) { System.out.println("敢打扰老子, 老子宰了你"); e.printStackTrace(); }
});
m1.start();; //开始睡
Thread.sleep(1000);
if(!m1.isInterrupted()) //检验是否产生中断, 如果没有则中断, 产生中断
{
System.out.println("我偷偷的打扰一下你的睡眠");
m1.interrupt();
}
4.执行结果:
72个小时的疯狂, 我需要补充精力
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at ThreadDemo.lambda0(ThreadDemo.java:26)
at java.lang.Thread.run(Thread.java:745)
我偷偷的打扰一下你的睡眠
敢打扰老子, 老子宰了你
5.所有正在执行的线程是可以被打断的, 中断线程必须进行异常处理
4.线程的强制执行
1.所谓的线程的强制执行知道是满足于某些条件之后, 某一个线程对象将可以一直独占资源, 一直到该线程的程序执行结束
2.范例, 观察一个没有强制执行的程序
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<100; x++) { System.out.println("[霸道的main线程]number = " + x); } }
}
3.结果:
[霸道的main线程]number = 0
玩耍的线程执行, x= 0
[霸道的main线程]number = 1
玩耍的线程执行, x= 1
[霸道的main线程]number = 2
玩耍的线程执行, x= 2
[霸道的main线程]number = 3
玩耍的线程执行, x= 3
[霸道的main线程]number = 4
玩耍的线程执行, x= 4
[霸道的main线程]number = 5
玩耍的线程执行, x= 5
[霸道的main线程]number = 6
...
4.这个时候主线程和子线程都在交替执行着, 但是如果说, 你希望主线程独占执行, 那么我们就可以使用Thread中的类方法, 进行强制执行
强制执行: public final void join() throws InterruptedException
5.范例
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) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "执行, x= " + x); } }, "玩耍的线程"); thread.start(); for(int x = 0; x<100; x++) { System.out.println("[霸道的main线程]number = " + x); } }
}
6.结果:
[霸道的main线程]number = 0
[霸道的main线程]number = 1
[霸道的main线程]number = 2
[霸道的main线程]number = 3
[霸道的main线程]number = 4
[霸道的main线程]number = 5
[霸道的main线程]number = 6
[霸道的main线程]number = 7
[霸道的main线程]number = 8
[霸道的main线程]number = 9
[霸道的main线程]number = 10
[霸道的main线程]number = 11
[霸道的main线程]number = 12
[霸道的main线程]number = 13
[霸道的main线程]number = 14
[霸道的main线程]number = 15
[霸道的main线程]number = 16
[霸道的main线程]number = 17
[霸道的main线程]number = 18
[霸道的main线程]number = 19
[霸道的main线程]number = 20
[霸道的main线程]number = 21
[霸道的main线程]number = 22
[霸道的main线程]number = 23
[霸道的main线程]number = 24
...
7.在进行线程强制执行的时候, 一定要获取强制执行线程对象之后才可以执行join()调用
5.线程的礼让
1.线程的礼让是指先将资源让出去, 让别人先执行。线程的礼让可以使用Thread中提供的方法
礼让: public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
2.范例, 礼让操作:
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 == 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("[霸道的main线程]number = " + x); } }
}
执行结果:
玩耍的线程礼让
[霸道的main线程]number = 0
玩耍的线程执行, x= 0
[霸道的main线程]number = 1
玩耍的线程执行, x= 1
[霸道的main线程]number = 2
玩耍的线程执行, x= 2
玩耍的线程礼让
[霸道的main线程]number = 3
玩耍的线程执行, x= 3
[霸道的main线程]number = 4
玩耍的线程执行, x= 4
[霸道的main线程]number = 5
...
3.礼让执行的时候, 每一次调用yeild()方法都只会礼让一次当前的资源
6.线程的优先级
1.从理论上来讲, 线程的优先级越高, 越有可能先执行(越有可能先抢占到资源)。
2.在Thread类里面针对于优先级的操作提供有如下的两个处理方法
设置线程的优先级: public final void setPriority(int newPriority)
获取线程的优先级:public final int getPriority()
3.在进行优先级定义的时候都是通过int类型的数字来完成的, 而对于此数字的选择在Thread类中, 就定义有三个常量
最高优先级:public static final int MAX_PRIORITY 10
中等优先级:public static final int NORM_PRIORITY, 也是默认优先级 5
最低优先级:public static final int MIN_PRIORITY 1
4.范例:观察优先级
public class ThreadDemo {
public static void main(String [] args) throws Exception{
// Thread mainThread = Thread.currentThread(); //获取主线程 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.MAX_PRIORITY); threadB.setPriority(Thread.MIN_PRIORITY); threadC.setPriority(Thread.MIN_PRIORITY); threadA.start(); threadB.start(); threadC.start(); }
}
5.结果:
public class ThreadDemo {
public static void main(String [] args) throws Exception{
// Thread mainThread = Thread.currentThread(); //获取主线程 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.MAX_PRIORITY); threadB.setPriority(Thread.MIN_PRIORITY); threadC.setPriority(Thread.MIN_PRIORITY); threadA.start(); threadB.start(); threadC.start(); }
}
6.主方法是主线程, 那么, 主线程的优先级是多少:
System.out.println(Thread.currentThread().getPriority());
7.结果:
5
8.主线程是属于中等优先级, 而默认创建的线程也是中等优先级。