关于java多线程的概念以及基本用法:java多线程基础
1,停止线程
停止线程意味着在线程执行完之前停止正在做的操作,即立刻放弃当前的操作,这并不容易。停止线程可以用Thread.stop()方法,但是这个方法不安全,所以不建议使用,还有一个方法就是Thread.interrupt()方法,但是这个方法不会终止一个正在运行的线程,需要添加一个判断才可以完成线程的停止
1.1,停不下来的线程
- public void interrupt()
将调用者线程的中断状态设为true
Thread.interrupt()方法只是在当前线程中打了一个停止的标记,并不是直接将线程停止
class MyThread_1 extends Thread{
@Override
public void run() {
super.run();
for(int i=0;i<10000;i++) {
System.out.println("i="+(i+1));
}
}
}
public class Demo1_7_1 {
public static void main(String[] args) {
try {
MyThread_1 thread = new MyThread_1();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
从结果可以看到,使用thread.interrupt()线程并未停止
1.2,判断线程是否是停止状态
- public static boolean interrupted
只能通过Thread.interrupted()调用
class MyThread_2 extends Thread{
@Override
public void run() {
super.run();
for(int i=0;i<10000;i++) {
System.out.println("i="+(i+1));
}
}
}
public class Demo1_7_2 {
public static void main(String[] args) {
try {
MyThread_2 thread = new MyThread_2();
thread.start();
Thread.sleep(2000);
thread.interrupt();
System.out.println("是否停止1?="+thread.interrupted());
System.out.println("是否停止2?="+thread.interrupted());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end");
}
}
运行结果:
当前线程是main并没有中断过,所以打印结果都是false
将main函数代码改为
Thread.currentThread().interrupt();
System.out.println("是否停止1?="+Thread.interrupted());
System.out.println("是否停止2?="+Thread.interrupted());
System.out.println("end");
结果为
是否停止1?=true
是否停止2?=false
end
为什么第二个值是false?这是因为第一次调用Thread.interrupted()返回当前线程中断状态,然后会将线程的中断状态设为false
- public boolean isInterrupted()
判断调用者线程的中断状态
讲main函数修改
try {
MyThread_2 thread = new MyThread_2();
thread.start();
Thread.sleep(2000);
thread.interrupt();
System.out.println("是否停止1?="+thread.isInterrupted());
System.out.println("是否停止2?="+thread.isInterrupted());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end");
运行结果是:
。。。
。。。。
i=9997
i=9998
i=9999
i=10000
是否停止1?=false
是否停止2?=false
end
很神奇这里返回结果都是false,想了半天,后来在网上查了资料明白是sleep函数的原因Thread.sleep(2000);休眠的是主线程,这里休眠的就是main函数,在这段时间里thread可能已经执行完了,所以thread.interrupt();也就起不到作用了,修改sleep函数时间,返回结果就都是true了
此方法作用:测试线程是否已经是中断状态,但是不会执行一次后将中断状态设置为false
1.3,停止线程–异常法
使用if语句判断线程是否是停止状态来控制后面的代码是否继续执行,但是无论是否停止线程,for循环外run方法里的代码都会执行,这里用throw new InterruptedException();来产生异常,从而结束线程,线程其余代码也不会执行了
class MyThread_3 extends Thread{
@Override
public void run() {
super.run();
try {
for(int i=0;i<500000;i++) {
if(this.isInterrupted()) {
System.out.println("已经是停止状态了,我要退出");
throw new InterruptedException();
}
System.out.println("i="+(i+1));
}
System.out.println("for下面");
}catch(InterruptedException e) {
System.out.println("进Mythread类run方法中的catch");
e.printStackTrace();
}
}
}
public class Demo1_7_3 {
public static void main(String[] args) {
try {
MyThread_3 thread = new MyThread_3();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end");
}
}
结果:
。。。。
。。。。。
i=366068
i=366069
i=366070
end
已经是停止状态了,我要退出
进Mythread类run方法中的catch
java.lang.InterruptedException
at chapter_1.MyThread_3.run(Demo1_7_3.java:12)
1.4,停止线程–在Sleep状态
在sleep状态下停止某一线程会进入catch语句,并且清除停止状态值,使之变成false
class MyThread_4 extends Thread{
@Override
public void run() {
super.run();
try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (Exception e) {
// TODO: handle exception
System.out.println("在沉睡中被停止进入catch"+this.isInterrupted());
e.printStackTrace();
}
}
}
public class Demo1_7_4 {
public static void main(String[] args) {
try {
MyThread_4 thread = new MyThread_4();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (Exception e) {
// TODO: handle exception
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end");
}
}
结果:
run begin
end
在沉睡中被停止进入catchfalse
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at chapter_1.MyThread_4.run(Demo1_7_4.java:10)
1.5,停止线程–暴力停止
所谓暴力停止就是最直接的方法了–stop(),这种方法直接让线程停止,但是这也会引来一些问题,比如线程的安全问题,不建议使用
1.6,停止线程–使用return
将方法interrupt()与return结合使用也可以实现停止线程
class MyThread_8 extends Thread{
@Override
public void run() {
super.run();
while(true) {
if(this.isInterrupted()) {
System.out.println("停止了!");
return;
}
System.out.println("timer="+System.currentTimeMillis());
}
}
}
public class Demo1_7_8 {
public static void main(String[] args) throws InterruptedException{
MyThread_8 t = new MyThread_8();
t.start();
Thread.sleep(2000);
t.interrupt();
}
}
结果:
。。。
。。。
timer=1533907137644
timer=1533907137644
timer=1533907137644
timer=1533907137644
timer=1533907137644
timer=1533907137644
停止了!
1.7,yield方法
yield()方法作用是放弃当前CPU资源,让给其他线程去使用,但是放弃时间不确定
1.8,线程优先级
操作系统会对线程进行划分优先级,优先级高的线程会优先分配到资源,类似于现实中的VIP,Java将线程从1到10划分十个等级,默认优先级为NORM_PRIORITY,设置优先级用setPriority()
setPriority()源码:
public final void setPriority(int i)
{
checkAccess();
if(i > 10 || i < 1)
throw new IllegalArgumentException();
ThreadGroup threadgroup;
if((threadgroup = getThreadGroup()) != null)
{
if(i > threadgroup.getMaxPriority())
i = threadgroup.getMaxPriority();
setPriority0(priority = i);
}
}
- public final static int MIN_PRIORITY=1;
- public final static int NORM_PRIORITY=5;
- public final static int MAX_PRIORITY=10;
此外线程还具有继承性,若线程A启动线程B,则B具有A的优先级
1.9,守护线程
在Java线程中有两种线程,一种是用户线程一种是守护线程,我们常说的操作系统中并没有守护线程这一说,原因是Java是构建在JVM之上的。顾名思义,守护线程具有陪伴的意思,当进程中不存在非守护线程时,守护线程就会自动销毁。
Daemon作用是为了其他线程的运行提供便利服务,只有当最后一个非守护线程结束时,守护线程才会随着JVM一同结束工作,守护线程典型的例子就是GC
class MyThread_11 extends Thread{
private int i=0;
@Override
public void run() {
super.run();
try {
while(true) {
i++;
System.out.println("i="+(i));
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Demo1_11 {
public static void main(String[] args) {
try {
MyThread_11 thread = new MyThread_11();
thread.setDaemon(true);
thread.start();
Thread.sleep(5000);
System.out.println("守护线程离开了!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
i=1
i=2
i=3
i=4
i=5
守护线程离开了!
2018.9.9补充:
突然对this与Thread.currentThread()产生了疑问,下面来对这个区别来介绍一下:
创建一个MyObject类:
public class MyThread extends Thread{
public MyThread() {
}
@Override
public void run() {
System.out.println("Thread.currentThread.getName= "
+Thread.currentThread().getName());
System.out.println("this.getName= "+this.getName());
}
}
测试类:
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t = new Thread(myThread);
t.start();
}
}
结果:
Thread.currentThread.getName= Thread-1
this.getName= Thread-0
显然这里this和Thread.currentThread()指向的不是同一个线程,看一下Thread源码:
Thread t = new Thread(myThread)这句传入的对象MyThread就是源码里的target对象,Thread类的构造方法会给线程一个默认的名字,从”Thread-0”开始
this.getName()其实就是target.getName(),返回的是执行MyThread myThread = new MyThread()的线程名,而Thread.currentThread().getName()返回的是t.getName(),返回的是Thread t = new Thread(myThread)这句创建的线程