多线程的常用操作方法

主方法本身就是一个线程,所有的线程都是通过主线程创建并启动的。run()方法相当于主类

中的main方法

class MyThread implements Runnable{
	public void run() {
		System.out.println("当前线程:" +Thread.currentThread().getName());
	} 
}
public class Line{
	public static void main(String[] args) {
		MyThread mt=new MyThread();
		mt.run();//直接通过对象调用run()方法
		new Thread(mt).start();//通过线程调用
	}
}

结果:

当前线程:main
当前线程:Thread-0

1.线程休眠 sleep方法

线程休眠:指的是让线程暂缓执行一下,等到了预计时间之后在恢复执行。

线程休眠会交出CPU,让CPU去执行其他的任务。但是有一点要注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。

使线程进入阻塞态

方法:public static native void sleep(long millis) throws InterruptedException

休眠时间使用毫秒作为单位

class MyThread implements Runnable{
    public void run() {
        for(int i=0;i<1000;i++) {
            try {
                  Thread.sleep(1000);
            } catch(InterruptedException e) {
                e.printStackTrace();
                }
        System.out.println("当前线程:"+Thread.currentThread().getName()+",i="+i);
        }    
    }
}
public class Line{
    public  static void main(String[] args) {
        MyThread mt=new MyThread();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    }

}

结果:

当前线程:Thread-2,i=0
当前线程:Thread-0,i=0
当前线程:Thread-1,i=0
当前线程:Thread-2,i=1
当前线程:Thread-0,i=1
当前线程:Thread-1,i=1
当前线程:Thread-2,i=2
当前线程:Thread-1,i=2
当前线程:Thread-0,i=2
当前线程:Thread-2,i=3
当前线程:Thread-0,i=3
当前线程:Thread-1,i=3
当前线程:Thread-2,i=4
当前线程:Thread-1,i=4
当前线程:Thread-0,i=4

通过以上代码会错误的认为这三个线程是同时休眠的,但是千万要记住,所有的代码是依次进入到run()方法的,真正进入到方法的对象可能是多个,也可能时一个。进入代码的顺序可能有差异,但是总体的执行是并发执行的。

2.线程让步 yied()方法

暂停当前正在执行的线程对象,并执行其他线程。

调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会解放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获得CPU执行时间的机会,如果没有同等优先级的线程,那么yield()方法什么也不做。

注意:调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只是需要等待重新获取CPU执行时间。

class MyThread implements Runnable{
	public void run() {
		for(int i=0;i<5;i++) {
			Thread.yield();
		System.out.println("当前线程:"+Thread.currentThread().getName()+",i="+i);
		}
	}
}
public class Line{
	public  static void main(String[] args) {
		MyThread mt=new MyThread();
		new Thread(mt).start();
		new Thread(mt).start();
		new Thread(mt).start();
	}
}

结果:

当前线程:Thread-0,i=0
当前线程:Thread-2,i=0
当前线程:Thread-1,i=0
当前线程:Thread-2,i=1
当前线程:Thread-0,i=1
当前线程:Thread-2,i=2
当前线程:Thread-1,i=1
当前线程:Thread-0,i=2
当前线程:Thread-2,i=3
当前线程:Thread-1,i=2
当前线程:Thread-0,i=3
当前线程:Thread-2,i=4
当前线程:Thread-1,i=3
当前线程:Thread-0,i=4
当前线程:Thread-1,i=4

3.join()方法

等待该线程终止,意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run()方法先执行完毕之后再开始执行主线程。

class MyThread implements Runnable{
	public void run() {
		try {
			
		
		System.out.println("\r\n主线程睡眠前的时间");
		Line.printTime();
		Thread.sleep(5000);
		System.out.println(Thread.currentThread().getName());
		System.out.println("睡眠结束的时间");
		Line.printTime();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
public class Line{
	public static void main(String[] args) throws InterruptedException {
		MyThread mt=new MyThread();
		Thread thread=new Thread(mt,"子线程A");
		thread.start();
		System.out.print(Thread.currentThread().getName());
		thread.join();
		System.out.println("代码结束");
		
	}
	public static void printTime() {
		Date date=new Date(12);
		DateFormat format=new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
		String time=format.format(date);
		System.out.println(time);
	}
}

结果:

main
主线程睡眠前的时间
1970-01-01 08:00:00
子线程A
睡眠结束的时间
1970-01-01 08:00:00
代码结束

多线程停止,有三种方法:

1.设置标记位,可以是线程正常退出。

2.使用stop()方法强制使线程退出,但是该方法不太安全所以已经被遗弃了。

3.使用Thread类中的一个interrupt()可以中断线程。

设置标志位使线程退出。

class MyThread implements Runnable{
	private boolean flag=true;
	public void run() {
		int i=1;
		while(flag) {
			try {
				Thread.sleep(1000);
				System.out.println("第"+i+"次执行,线程名称为"+Thread.currentThread().getName());
				i++;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	public void setFlag(boolean flag) {
		this.flag=flag;
	}
}
public class Line{
	public static void main(String[] args) throws InterruptedException {
		MyThread myThread=new MyThread();
		
		Thread thread1=new Thread(myThread,"子线程A");
		thread1.start();
		Thread.sleep(2000);
		myThread.setFlag(false);
		System.out.println("代码结束");
		
	}
}

结果:

第1次执行,线程名称为子线程A
第2次执行,线程名称为子线程A
代码结束

使用stop方法退出不安全已经被遗弃了。

为什么不安全?因为stop会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程

就会立即停止,假如一个线程正在执行:synchronized void{x=3;y=4;} 由于方法都是同步的,多个线程访问时总能保证x,y被同时赋值。而如果一个线程正在执行到3;时,被调用了stop()方法,即使在同步块中,它也会马上stop了,这样就产生了不完整的残废数据。

使用Thread.interrupt()

class  MyThread implements Runnable{
	private boolean flag=true;
	public void run() {
		int i=1;
		while(flag) {
			try {
//				这是阻塞之后,线程被调用了interrupte()方法;
//				清除终端标志位,就会抛出一个异常
//				java.lang.InterruptedException
				Thread.sleep(1000);
				boolean bool=Thread.currentThread().isInterrupted();
				if(bool) {
					System.out.println("非阻塞情况下执行该操作。。。线程状态"+bool);
					break;
				}
				System.out.println("第"+i+"次执行,线程名称为:"+Thread.currentThread().getName());
                            i++;
			} catch (InterruptedException e) {
				
			
				System.out.println("退出了");
//				这里退出阻塞状态,且中断标志被系统会自动清除,
//				并且重新设置为false,所以此处bool为false
				boolean bool=Thread.currentThread().isInterrupted();
				System.out.println(bool);
				return;
			}
			
		}
	}
	public void setFlag(boolean flag) {
		this.flag=flag;
	}
}
public class Line{
	public static void main(String[] args) {
		MyThread myThread=new MyThread();
		Thread thread1=new Thread(myThread,"子线程A");
		thread1.start();
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		thread1.interrupt();
		System.out.println("代码结束");
	}
}

结果:

第1次执行,线程名称为:子线程A
第2次执行,线程名称为:子线程A
第3次执行,线程名称为:子线程A
代码结束
退出了
false

interrupt()方法只是改变中断状态而已,它不会中断正在运行的一个线程。这一方法实际完成的是,给受阻塞的线程发出一个中断信号,这样受阻线程就得以退出阻塞的状态。

然而interrupte()方法并不会立即执行中断操作:具体而言,这个方法只会给线程设置一个为true的中断标志(中断标志只是一个布尔类型的变量),而设置之后,则根据线程当前的状态进行不同的后续操作。如果线程的当前状态为非阻塞状态,那么仅仅是线程的中断标志被修改为true而已;如果线程的当前状态为阻塞状态,那么在中断标志位设置为true后,还会有如下三种情况之一的操作:

1.如果是wait,sleep以及join三个方法引起的阻塞,那么会将线程的中断标志重新设置为false,并抛出一个interrupttedException;

2.如果在中断时,线程正处于非阻塞状态,则中断标志修改为true,而在此基础上,一旦进入阻塞状态,则按照阻塞状态的情况来进行处理;例如,一个线程在运行状态中,其中断标志位被设置为true之后,一旦线程调用了wait sleep join方法中的一种,立马抛出一个interruptedException,而且中断标志位被线程自动清除,重新设置为false.

综上:调用线程类的interrupted方法,其本质只是设置线程的中断标志,将中断标志设置为true,并根据线程状态决定是否抛出异常。因此,通过interrupted方法真正实现线程的中断原理是:开发人员根据中断标志的具体值,来决定如何退出线程。

线程正常执行状态下(除了wait sleep join)使用Thread.interrupt(),会将线程状态置为打断状态,根据此状态人为进行线程终止。

线程中出现wait(),sleep(),join()再调用Thread.interrupt()会抛出线程中断异常,而后在catch块中人为进行线程终止。

线程优先级

线程的优先级越高越有可能先执行,但仅仅是可能而已。

在Thread类中提供有如下优先级方法:

设置优先级:public final void setPriority(int newPriority)

1.最高优先级:public final static int MAX_PRIORITY=10;

2.中等优先级:public final static int NORM_PRIORITY=5;

3.最低优先级:public final static int MIN_PRIORITY=1;

取得优先级: public final int getPriority()

class MyThread implements Runnable{
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println("当前线程:"+Thread.currentThread().getName()+",i="+i);
		}
	}
}
public class Line{
	public static void main(String[] args) {
		MyThread mt=new MyThread();
		Thread t1=new Thread(mt,"1");
		Thread t2=new Thread(mt,"2");
		Thread t3=new Thread(mt,"3");
		t1.setPriority(Thread.MIN_PRIORITY);
		t2.setPriority(Thread.MIN_PRIORITY);
		t3.setPriority(Thread.MAX_PRIORITY);
		t1.start();
		t2.start();
		t3.start();
	}
}

主方法是一个中等优先级的方法

public class Line{
    public static void main(String[] args) {
    System.out.println(Thread.currentThread().getPriority());
    }

}

守护线程

守护线程是一种特殊的线程,它属于是一种陪伴线程。

java中有两种线程:用户线程和守护线程。可以通过isDaemon()方法来区分它们:如果返回false,则说明该线程是“用户线程”,否则就是“守护线程”。

典型的守护线程就是垃圾回收线程。只要当前JVM进程中存在任何一个非守护线程没有结束,守护线程就在工作;只有当最后一个非守护线程结束时,守护线程才会随着JVM一同停止工作。

注意:主线程main是用户线程。

class A implements Runnable{
	private int i;
	
	public void run() {
		try {
		while(true) {
			i++;
			System.out.println("线程名称:"+Thread.currentThread().getName()+",i="+i+
					",是否为守护线程:"+Thread.currentThread().isDaemon());
			
				Thread.sleep(1000);
		}
			} catch (InterruptedException e) {
				System.out.println("线程名称:"+Thread.currentThread().getName()+"中断线程了");
			}
		}
	}
public class Line{
	public static void main(String[] args) {
		Thread thread1=new Thread(new A(),"子线程A");
		//设置线程A为守护线程,此语句必须在start方法之前执行
		thread1.setDaemon(true);
		thread1.start();
		
		Thread thread2=new Thread(new A(),"子线程B");
		thread2.start();
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//中断非守护线程
		thread2.interrupt();
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("代码结束");
	}
}

结果:

线程名称:子线程B,i=1,是否为守护线程:false
线程名称:子线程A,i=1,是否为守护线程:true
线程名称:子线程B,i=2,是否为守护线程:false
线程名称:子线程A,i=2,是否为守护线程:true
线程名称:子线程B,i=3,是否为守护线程:false
线程名称:子线程A,i=3,是否为守护线程:true
线程名称:子线程B,i=4,是否为守护线程:false
线程名称:子线程A,i=4,是否为守护线程:true
线程名称:子线程B中断线程了
线程名称:子线程A,i=5,是否为守护线程:true
线程名称:子线程A,i=6,是否为守护线程:true
线程名称:子线程A,i=7,是否为守护线程:true
线程名称:子线程A,i=8,是否为守护线程:true
线程名称:子线程A,i=9,是否为守护线程:true
线程名称:子线程A,i=10,是否为守护线程:true
线程名称:子线程A,i=11,是否为守护线程:true
线程名称:子线程A,i=12,是否为守护线程:true
线程名称:子线程A,i=13,是否为守护线程:true
代码结束

猜你喜欢

转载自blog.csdn.net/xjy22/article/details/80102200