关于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,郑州不孕不育好医院:http://www.zzchyy110.com/

  将方法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)这句创建的线程