Java---多线程---遇见它

线程的创建:

方法1:

    通过继承Thread覆盖run方法。

public class MyThread extends Thread{

	@Override
	public void run() {
		System.out.println("MyThread 通过继承Thread覆盖run方法");
	}
}

方法2:

    通过实现Runnable接口,并且实现run方法。

public class MyRun implements Runnable{

	@Override
	public void run() {
		System.out.println("MyRun 通过实现Runnable接口的run方法");
	}

}

多线程的调度:

Java的多线程是抢占式的运行方式。

setPriority()

    设置线程的优先级,最低1,最高10,默认5.

sleep()

Thread类的sleep()方法对当前线程操作,是静态方法。sleep()的参数指定以毫秒为单位的线程休眠时间。除非因为中断而提早恢复执行,否则线程不会在这段时间之前恢复执行。

interrupt()

一个线程可以调用另外一个线程的interrupt()方法,这将向暂停的线程发出一个InterruptedException。变相起到唤醒暂停线程的功能。Thread类的方法interrupt(),是一种强制唤醒的技术。

public class Demo {
	public static void main(String[] args) {
		MyThread t1 = new MyThread(1);
		MyThread t2 = new MyThread(2);
		//setPriority() 是相对调度
//		t1.setPriority(5);
//		t2.setPriority(2);
		
		
		t1.start();
		t2.start();
		
		try {
			Thread.sleep(1000);
			t1.interrupt();//强制唤醒
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
class MyThread extends Thread{
	private int start;

	public MyThread(int start) {
		this.start = start;
	}
	
	@Override
	public void run() {
		if (start==1) {
			try {
				Thread.sleep(3000);//睡3秒
			} catch (InterruptedException e) {
				System.out.println("我被踹醒了!!");
			}
		}
		for (int i = start; i < 100; i+=2) {
			System.out.print(i+" ");
		}
		System.out.println();
	}
}

yield()

    用来使具有相同优先级的线程获得执行的机会。如果具有相同优先级的其它线程是可运行的,yield()将把线程放到可运行池中并使另一个线程运行。如果没有相同优先级的可运行线程,则什么都不做。
    注意,执行一次yield()方法,该线程只是放弃当前这一次机会,然后又会重新和其它线程一起抢占CPU,很可能又比其它线程先抢到。

join()

    调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。它可以实现线程合并的功能,经常用于线程的绝对调度。

//yield()必须是同优先级线程之间才能调度
/*
 * yield()是主动让处一次机会给同优先级的其它线程,
 * 如果不存在同优先级的其它线程,则无效。
 * 
 * 注意,yield()让出一次机会后,还要和其它同优先级
 * 的线程进行再次抢该机会,再次抢时是不会让的。
 * 
 */

public class ScheduleDemo {

	public static void main(String[] args) {
		
		Thread t1 = new MyRun(1);
		Thread t2 = new MyRun(2);
		
		t1.start();
		t2.start();
		
		try {
			t1.join();//把t1并入当前线程 ---绝对调度
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		for(int i=1000;i<1051;i++){
			System.out.print(i+" ");
		}
		System.out.println();
		
	}

}

class MyRun extends Thread{
	private int start;
	
	public MyRun(int start) {
		this.start = start;
	}

	@Override
	public void run() {
		
		for(int i=start;i<100;i+=2){
//			if(start==2){
//				yield(); //相对调度
//			}
			System.out.print(i+" ");
		}
		System.out.println();
	}
	
}

wait()

    当前线程进入对象的wait pool

notify()/notifyAll()

唤醒对象的wait pool中的一个/所有等待线程

下面4个类演示wait()、notify()和notifyAll()

public class Buffer {
	private int value;//共享变量
	
	private boolean isEmpty=true;//信号量---标记
	
	//生产
	public synchronized void put(int i){ //同步方法的锁是该方法的所有者(非静态方法是属于this对象,静态方法是属于类的),本例是this
		while(!isEmpty){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		value = i;//生产
		isEmpty=false;
		notify();//通知 等待池中随机选择的一个线程
		//notifyAll(); //通知等待池(和当前线程共用同一把锁的那些线程)中的所有线程
	}
	
	//消费
	public synchronized int get(){
		while(isEmpty){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		isEmpty=true;
		notify();
		
		return value;
	}
}
public class Sender extends Thread {
	private Buffer buf;
	public Sender(Buffer buf) {
		this.buf = buf;
	}

	@Override
	public void run() {
		for(int i=1; i<=8; i++){
			buf.put(i);
			System.out.println("Sender put:" + i);
			
			try {
				sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
} 
public class Receiver extends Thread{
	private Buffer buf ;

	public Receiver(Buffer buf) {
		this.buf = buf;
	}
	
	public void run() {
		for(int i=1;i<=8;i++){
			System.out.println("Receiver get:"+ buf.get() );
			try {
				sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

wait/notify 和 sleep方法区别

    wait和notify只能在它们被调用的实例的同步块内使用,而sleep()到处都可以用

    wait()和sleep()最大的区别:sleep()不释放对象锁,而wait()会释放,因此从效率方面考虑wait()方法更好

创建线程和启动线程并不相同

    在一个线程对新线程的Thread对象调用start()方法之前,这个线程并没有真正开始执行。Thread对象在其线程真正启动之前就已经存在了,而且其线程退出之后仍然存在。因此,仍可以控制或获取关于已创建的线程的信息,即使线程还没有启动或已经完成了。

结束线程

线程会以以下三种方式之一结束:

1)线程到达其run()方法的末尾,推荐这种方法,自然结束。
2)线程抛出一个未捕获到的Exception或Error。
3)另一个线程调用一个弃用的stop()方法。

守护程序线程(简称守护线程)

    我们提到过当Java程序的所有线程都完成时,该程序就退出,但这并不完全正确,因为程序中还隐藏的系统线程。
    随着程序的启动而启动,在运行期间一直捕捉符合它条件的处理,这样的线程就是守护线程。

猜你喜欢

转载自blog.csdn.net/qq_34928644/article/details/80167755