多线程学习笔记(四)---- Thread类的其他方法介绍

一、wait和 sleep的区别

  • wait可以指定时间也可以不指定时间,而sleep必须指定时间;
  • 在同步中时,对cpu的执行权和锁的处理不同;
    wait:释放执行权,释放锁;释放锁是为了别人notify
    sleep:释放执行权,不释放锁;sleep到时间后,自己醒,不需要别人来叫

二、线程的停止

1、前言

Thread类有stop()方法,但不建议使用。详细情况,看API介绍,已过时并具有安全隐患。
这里采用的是在run()方法里,结束线程。在任务中添加循环结构,只要控制循环就可以结束任务;而控制循环通常就用定义标记来完成。

2、错误代码

//线程任务
public class StopThread implements Runnable{
	private boolean flag = true;//为了控制线程任务的结束和开始
	
	public void run(){
		while(flag){
			System.out.println(Thread.currentThread().getName()+"......");
		}
	}
	//关闭线程任务
	public void setFlag(){
		flag = false;
	}
}

//测试类
public class Doem {
	public static void main(String[] args) {
		StopThread demo = new StopThread();
		
		Thread test1 = new Thread(demo);
		Thread test2 = new Thread(demo);
		
		test1.start();
		test2.start();
		
		int num = 1;
		for(;;){
			if(++num==50){
				demo.setFlag();
				break;
			}
			System.out.println("main....."+num);
		}
		System.out.println("main over");
	}
}
  • 错误原因
    上述代码存在一个安全隐患,即当一个线程处于线程池中,你是无法通过标记来结束任务。

3、隐患详解

(1)隐患展示

//设置多线程,并使该线程进入线程池中
public class StopThread implements Runnable{
	private boolean flag = true;//为了控制线程任务的结束和开始
	
	public synchronized void run(){
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"......");
		}
	}
	//关闭线程任务
	public void setFlag(){
		flag = false;
	}
}

//测试
public class Doem {
	public static void main(String[] args) {
		StopThread demo = new StopThread();
		
		Thread test1 = new Thread(demo);
		Thread test2 = new Thread(demo);
		
		test1.start();
		test2.start();
		
		int num = 1;
		for(;;){
			if(++num==50){
				demo.setFlag();
				break;
			}
			System.out.println("main....."+num);
		}
		System.out.println("main over");
	}
}
  • 现象:该程序并没有结束,因为除了主线程结束,其他线程并没有结束,它们进入线程池中
  • 解决思路:当一个线程处于线程池中,我们自然是没办法直接叫它结束任务的,但是,我们可以把它唤醒,然后再叫它结束。
  • 解决办法:Thread类的interrupt()方法
    将线程从线程池中移到锁池里,让线程具备cpu的执行资格,此时强制动作会抛出InterruptedException异常,记得要处理

4、完善代码

//多线程任务代码
public class StopThread implements Runnable{
	private boolean flag = true;//为了控制线程任务的结束和开始
	
	public synchronized void run(){
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				flag = false;//当interrupt()方法来强制中断时,由标记来结束线程任务
			}
			
			System.out.println(Thread.currentThread().getName()+"......");
		}
	}
	//关闭线程任务
	public void setFlag(){
		flag = false;
	}
}

//测试
public class Doem {
	public static void main(String[] args) {
		StopThread demo = new StopThread();
		
		Thread test1 = new Thread(demo);
		Thread test2 = new Thread(demo);
		
		test1.start();
		test2.start();
		
		int num = 1;
		for(;;){
			if(++num==50){
				//demo.setFlag();
				test1.interrupt();//关闭test1线程
				test2.interrupt();//关闭test2线程
				break;
			}
			System.out.println("main....."+num);
		}
		System.out.println("main over");
	}
}

三、void setDaemon(boolean on)

1、作用

  • 参数on为true,则将线程标记为守护线程;
  • 参数on为false,则将线程标记为用户线程;
  • 注意:该方法必须在启动线程前,调用!!!

2、守护线程与用户线程的介绍

  • 用户线程的关闭必须程序指定;
  • 而守护线程是当所有用户线程都关闭时,守护线程就自动关闭;
  • 在其他地方,例如:争取CPU执行权、消耗资源等等,守护线程与用户线程是一样的;

3、举例

public class StopThread implements Runnable{
	private boolean flag = true;//为了控制线程任务的结束和开始
	
	public synchronized void run(){
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				flag = false;//当interrupt()方法来强制中断时,由标记来结束线程任务
			}
			
			System.out.println(Thread.currentThread().getName()+"......");
		}
	}
	//关闭线程任务
	public void setFlag(){
		flag = false;
	}
}


public class Doem {
	public static void main(String[] args) {
		StopThread demo = new StopThread();
		
		Thread test1 = new Thread(demo);
		Thread test2 = new Thread(demo);
		
		test1.start();
		test2.setDaemon(true);//设置test2线程为守护线程
		test2.start();
		
		int num = 1;
		for(;;){
			if(++num==50){
				//demo.setFlag();
				test1.interrupt();//关闭test1线程
				//test2.interrupt();//test2线程在main、test1线程关闭后,自动关闭
				break;
			}
			System.out.println("main....."+num);
		}
		System.out.println("main over");
	}
}

四、void join()

1、作用

等待该线程终止;
在某个线程调用一个线程的join方法,代表:从此刻被调用join方法的线程为与锁池(即可以争取CPU),而另一个线程则会被放入线程池中。

2、举例

//测试
public class Doem {
	public static void main(String[] args) {
		Resource demo = new Resource();
		
		Thread test1 = new Thread(demo);
		Thread test2 = new Thread(demo);
		
		
		test1.start();
		
		test1.join();//test1位于锁池中,并且让mian线程位于线程池中
		
		test2.start();
		
		int num = 1;
		for(;;){
			System.out.println("main....."+num);
		}
	}
}

这里现象是:线程test1.join()后,只有test1线程在争取CPU的执行权;

public class Doem {
	public static void main(String[] args) {
		Resource demo = new Resource();
		
		Thread test1 = new Thread(demo);
		Thread test2 = new Thread(demo);
		
		
		test1.start();
		test2.start();
		
		test1.join();//test1位于锁池中,并且让mian线程位于线程池中
		
		int num = 1;
		for(;;){
			System.out.println("main....."+num);
		}
	}
}

这里现象是:只有主线程位于线程池中,而test1、test2线程位于锁池中争取CPU执行权

五、void setPriority(int newPriority)

1、作用

更改线程的优先级。参数newPriority范围为1-10,其中10最高;
通常有三个常量来方便指定:

  • MAX_PRIORITY:最高优先级,10;
  • MIN_PRIORITY :最低优先级,1;
  • NORM_PRIORITY :默认优先级,5;

六、String toString()

1、作用

返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

你可能感兴趣的:(多线程学习笔记(四)---- Thread类的其他方法介绍)