java多线程学习(一)

时间:2021-09-30 18:18:14
 

java多线程基础api使用

isInterrupted和interrupted的区别

isInterrupted只会返回线程状态并不改变,而interrupted会重置状态,

public class MyThread11 extends Thread{
	public static void main(String[] args) throws InterruptedException {
		Thread.currentThread().interrupt();
		System.out.println("是否停止?"+Thread.currentThread().isInterrupted());
		System.out.println("是否停止?"+Thread.interrupted());
		System.out.println("是否停止?"+Thread.interrupted());
	}
}
输出为:
是否停止?true
是否停止?true
是否停止?false

如何停止线程:

1,使用interrupt()和isInterrupted()方法组合判断,return或者捕获异常终止

注意使用interrupt()方法,无法停止线程

public class MyThread11 extends Thread{
	public static void main(String[] args) throws InterruptedException {
		MyThread11 mt=new MyThread11();
		mt.start();
		Thread.sleep(500);
		mt.interrupt();
		System.out.println("是否停止1?"+mt.isInterrupted());
		System.out.println("是否停止1?"+mt.isInterrupted());
	}
	public void run(){
		for(int i=0;i<10_0000;i++){
			if(this.isInterrupted()){
				System.out.println("interrupted状态,退出!");
			}
			System.out.println("i="+i);
//				Thread.sleep(1000);
		}
		System.out.println("for 下面");
	}
}

输出为:后面的还在执行

interrupted状态,退出!
i=95164
interrupted状态,退出!
i=95165

所以使用抛异常,捕获的方式,终止线程后续语句

public class MyThread11 extends Thread{
	public static void main(String[] args) throws InterruptedException {
		MyThread11 mt=new MyThread11();
		mt.start();
		Thread.sleep(500);
		mt.interrupt();
		System.out.println("是否停止1?"+mt.isInterrupted());
		System.out.println("是否停止1?"+mt.isInterrupted());
	}
	public void run(){
		try{
			for(int i=0;i<10_0000;i++){
				if(this.isInterrupted()){
					System.out.println("interrupted状态,退出!");
					throw new InterruptedException("手动抛异常");
				}
				System.out.println("i="+i);
	//				Thread.sleep(1000);
			}
			System.out.println("for 下面");
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		
	}
}
i=84326
interrupted状态,退出!
是否停止1?true
是否停止1?true
java.lang.InterruptedException: 手动抛异常
	at MyThread11.run(MyThread11.java:15)

所以interrupt()中断线程,并不能中断线程的执行,只是改变这个状态,

需要添加判断,再手动抛异常终止,

或者使用return 停止后续语句执行,如下面:

public class InterruptWithReturn extends Thread{
	private int i=0;
	public static void main(String[] args) throws InterruptedException {
		InterruptWithReturn mt=new InterruptWithReturn();
		mt.start();
		Thread.sleep(200);
		mt.interrupt();
	}
	public void run(){
		while(true){
			if(this.isInterrupted()){
				System.out.println("stoped by interrupt");
				break;
			}
			i++;
			System.out.println(i);
			
		}
	}
}


另外当sleep方法在执行的时候,遇到interrupt也会报异常,可以捕获,后续的语句也无法执行到

 
/**
 * 
 *先interrupt中断循环,再进入sleep的catch语句
 */
public class MyThread13 extends Thread{
	public static void main(String[] args) throws InterruptedException {
		MyThread13 mt=new MyThread13();
		mt.start();
//		Thread.sleep(500);
		mt.interrupt();
		System.out.println("是否停止1?"+mt.isInterrupted());
		System.out.println("是否停止1?"+mt.isInterrupted());
	}
	public void run(){
		try {
			for(int i=0;i<50_000;i++){
				System.out.println(i);
			}
			Thread.sleep(20000);
			System.out.println("after sleep");
		} catch (InterruptedException e) {
			System.out.println("先中断,for循环继续,直到遇到sleep方法,捕获到异常,才停止"
		            +this.isInterrupted());
			e.printStackTrace();
		}
	}
}


 
49998
49999
先中断,for循环继续,直到遇到sleep方法,捕获到异常,才停止false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at MyThread13.run(MyThread13.java:19)


 

2,stop()方法强行停止

不推荐的原因是强行stop会导致线程结束的一些清理工作不会执行,比如对锁定对象的解锁,导致不同步,另外stop.suspend.resume三个方法已经deprecate了,后续将不再支持.

3,使用额外标记停止

利用线程通信,添加判断,适当时机停止线程

public class MyThread16 extends Thread{
	private  boolean isRun=true;
	
	public  boolean isRun() {
		return isRun;
	}
	public  void setRun(boolean isRun) {
		this.isRun = isRun;
	}
	public static void main(String[] args) throws InterruptedException {
		MyThread16 mt=new MyThread16();
		mt.start();
		Thread.sleep(100);
		if(mt.isRun){
			mt.setRun(false);
		}
		System.out.println(mt.isAlive());
		System.out.println(mt.isInterrupted());
	}
	public void run(){
		while(true){
			System.out.println("running...");
			if(!isRun){
				System.out.println("stop");
				return;
			}
		}
	}
}

suspend和resume

使用示例:
package suspendAndResume;

public class MyThread extends Thread {
	private long i=0;

	public long getI() {
		return i;
	}

	public void setI(long i) {
		this.i = i;
	}
	@Override
	public void run(){
		while(true){
			i++;
		}
	}
	
}
package suspendAndResume;

public class Run {

	public static void main(String[] args) {
		try{
			MyThread mt=new MyThread();
			mt.start();
			//A
			Thread.sleep(5000);
			mt.suspend();
			System.out.println("A="+System.currentTimeMillis()+" i="+mt.getI());//A=1525146789091 i=2436609039
			Thread.sleep(5000);
			System.out.println("A="+System.currentTimeMillis()+" i="+mt.getI());//A=1525146794091 i=2436609039
			mt.resume();
			Thread.sleep(5000);
			System.out.println("B="+System.currentTimeMillis()+" i="+mt.getI());//B=1525146799091 i=4862628335
			mt.suspend();
			Thread.sleep(5000);
			System.out.println("B="+System.currentTimeMillis()+" i="+mt.getI());//B=1525146804091 i=4862666032
			
			
		}catch(InterruptedException e){
			
		}
		
	}

}

suspend和resume缺点:

    1,独占

package suspendAndResume;

public class SynchronizedObject {
	synchronized public void printString(){
		System.out.println("beging---");
		if(Thread.currentThread().getName().equals("a")){
			System.out.println("a线程suspend");
			Thread.currentThread().suspend();
		}
		System.out.println("end---");
		
	}
}
package suspendAndResume;

public class Run2 {

	public static void main(String[] args){
		try{
			final SynchronizedObject object=new SynchronizedObject();
			Thread t1=new Thread(){
				public void run(){
					object.printString();
				}
			};
			t1.setName("a");
			t1.start();
			Thread.sleep(1000);
			Thread t2=new Thread(){
				public void run(){
					System.out.println("t2 尝试进入printString方法");
					object.printString();
					System.out.println("没有打印begin,因为printString被t1独占,且t1被suspend了");
				}
			};
			t2.start();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}

}

beging---
a线程suspend
t2 尝试进入printString方法

程序会一直阻塞在这里,无法进行下去.另外对println方法的独占会导致其他线程的println阻塞,

suspend造成多线程的不同步

package suspendAndResume;

public class MyObject {
	private String username="1";
	private String passwd="1111";
	public void setValue(String u,String p){
		this.username=u;
		if("a".equals(Thread.currentThread().getName())){
			System.out.println("a线程suspend");
			Thread.currentThread().suspend();
		}
		this.passwd=p;
	}
	public void printUAndP(){
		System.out.println(username+":"+passwd);
	}
}
package suspendAndResume;
/*
 * 演示suspend方法导致不同步的问题
 */
public class Run4 {

	public static void main(String[] args) throws InterruptedException{
		MyObject mo=new MyObject();
		Thread t1=new Thread(){
			@Override
			public void run(){
				mo.setValue("a", "aaa");
			}
		};
		t1.setName("a");
		t1.start();//a线程会一直挂起,导致程序阻塞,并且passwd还是初始的值,
		Thread.sleep(1000);//sleep main进程,
		Thread t2=new Thread(){
			@Override
			public void run(){
				mo.printUAndP();
			}
		};
		t2.start();
		
	}

}

yield

示例:

package yield;

public class MyThread extends Thread {
	@Override
	public void run(){
		long sum=0;
		long begin=System.currentTimeMillis();
		for(int i=0;i<50_0000;i++){
			sum+=i;
//			注释后输出:
//			sum=124999750000
//					用时:2ms
//			不注释输出:
//			sum=124999750000
//			用时:62ms
			Thread.yield();
		}
		long end=System.currentTimeMillis();
		System.out.println("sum="+sum);
		System.out.println("用时:"+(end-begin)+"ms");
	}
}
package yield;
/*
 * 通过循环yiel的,耗时的增加,演示yield放弃cpu时间的功能,
 */
public class Run {

	public static void main(String[] args) {
		MyThread mt=new MyThread();
		mt.start();
	}

}

优先级:

源码:

	public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        //判断是否大于10和小于0
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        //设置的线程优先级不能高于该线程所在组的最大优先级,
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

优先级有:

规律性:优先级高的的(1-10,越大优先级越高)优先获得cpu时间,

随机性:并不是优先级高的线程一定比优先级低的先执行

从表现上来说,优先级高的线程体执行的速度要快些,因为获得cpu时间多

daemon

setDaemon(true)方法设置成daemon进程,当有没有其他的非daemon进程存在时,daemon进程也就没有存在的必要,会自动结束


参考:《Java多线程编程核心技术》