Java之多线程加强(多线程调度与控制)

Java基础知识学了好久了,今天再拿来复习一下。

helloworld

先来一个helloworld热热身

Test.java

package cn.hncu.thread.hello;

public class Test {

	public static void main(String[] args) {
		MyThread mt1=new MyThread(0);//偶数
		MyThread mt2=new MyThread(1); //奇数
		mt1.start();
		mt2.start();
		
		MyRun mr1=new MyRun(50);
		Thread t3=new Thread(mr1);
		MyRun mr2=new MyRun(51);
		Thread t4=new Thread(mr2);
		t3.start();
		t4.start();
	}

}

MyThread.java

package cn.hncu.thread.hello;

public class MyThread  extends Thread{
	Integer first;
	 public MyThread(Integer first) {
		this.first=first;
	}
	@Override
	public void run() {
		for(int i=first;i<50;i+=2){
			System.out.print(i+" ");
		}
		System.out.println();
	}
	
}

MyRun.java

package cn.hncu.thread.hello;

public class MyRun implements Runnable{
	Integer first;
	public MyRun(Integer first) {
		this.first=first;
	}
	@Override
	public void run() {
		for(int i=first;i<100;i+=2){
			System.out.print(i+" ");
		}
		System.out.println();
	}
	
}

new出来了四个线程跑跑


多线程调度与控制

这里将通过四个版本代码来演示多线程调度与控制

v1版本

★ Java的多线程是抢占式的运行方式。 ★ setPriority()

★ sleep()方法

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

★ interrupt()方法

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

Schedule.java

package cn.hncu.thread.schedule.v1;

public class Schedule {

	public static void main(String[] args) {
		MyThread t1=new MyThread(0);
		MyThread t2=new MyThread(1);
		//setPriority() 相对调度
		//t1.setPriority(5);
		//t2.setPriority(6);
		
		t1.start();
		//t1.start();  //如果一个线程已经启动,再次启动会出异常java.lang.IllegalThreadStateException
		t2.start();
		//唤醒别人
		t1.interrupt(); //mian 线程强制唤醒t1,如果t1正在sleep,那么就停止sleep,往后继续执行代码
	}

}

MyThread.java

package cn.hncu.thread.schedule.v1;

public class MyThread extends Thread{
	private Integer first;
	public MyThread(Integer first) {
		this.first=first;
	}
	@Override
	public void run() {
		if(first==0){
			try {
				Thread.sleep(1000); //主动睡1000毫秒=1s
			} catch (InterruptedException e) {
				System.out.println("我被强制唤醒了.......要继续干活了");
			}
		}
		for(int i=first;i<50;i+=2){
			System.out.print(i+" ");
		}
		System.out.println();
	}

	
}


v2版本

★ yield()方法

用来使具有相同优先级的线程获得执行的机会。如果具有相同优先级的其它线程是可运行的,yield()将把线程放到可运行池中并使另一个线程运行。如果没有相同优先级的可运行线程,则什么都不做。

注意,执行一次yield()方法,该线程只是放弃当前这一次机会,然后又会重新和其它线程一起抢占CPU,很可能又比其它线程先抢到。

★ join()方法

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

Schedule.java

package cn.hncu.thread.schedule.v2;

public class Schedule {

	public static void main(String[] args) {
		MyThread t1=new MyThread(0);
		MyThread t2=new MyThread(1);
		//setPriority() 相对调度
		t1.setPriority(6);
		t2.setPriority(6);
		
		t1.start();
		try {
			t1.join(); //把t1线程剩下的代码合并到当前线程来执行。即:把t1线程中剩下的代码在此处先执行完,再执行后面的代码
		} catch (InterruptedException e) {
			System.out.println("线程合并异常.....");
		}
		t2.start();
	}

}

MyThread.java

package cn.hncu.thread.schedule.v2;

public class MyThread extends Thread{
	private Integer first;
	public MyThread(Integer first) {
		this.first=first;
	}
	@Override
	public void run() {
		//if(first==0)
			//yield(); //主动让一次,且把机会让给其他同优先级的线程,否则什么也不做
		for(int i=first;i<50;i+=2){
			System.out.print(i+" ");
		}
		System.out.println();
	}

	
}

v3版本

★ wait()方法

当前线程进入对象的waitpool。

★notify()/notifyAll()方法

唤醒对象的waitpool中的一个/所有等待线程。

★suspend()、resume()和stop()这几个方法现在已经不提倡使用。

Schedule.java

package cn.hncu.thread.schedule.v3;

public class Schedule {

	public static void main(String[] args) {
		Object obj=new Object();
		MyThread t1=new MyThread(0,obj);
		MyThread t2=new MyThread(1,obj);
		t1.start();
		t2.start();
	}

}

MyThread.java

package cn.hncu.thread.schedule.v3;

public class MyThread extends Thread{
	private Integer first;
	private Object obj;
	private static boolean isWait=true;
	public MyThread(int first, Object obj) {
		this.first=first;
		this.obj=obj;
	}
	@Override
	public void run() {
		synchronized(obj){
			for(int i=first;i<50;i+=2){
				if(first==1&&i>25&&isWait){
					isWait=false;
					try {
						obj.wait();
					} catch (InterruptedException e) {
						System.out.println("被唤醒了.......");
					}
				}
					
				System.out.print(i+" ");
			}
			System.out.println();
			if(first==0){
				isWait=false; //为防止0线程先行拿到锁执行完毕以后,1线程一直wait
				obj.notify(); //只通知那些和自己处于同一等待池中的线程(被同一对象锁困住),任选一个
				//obj.notifyAll();//唤醒池中所有等待的线程
			}
		} //还锁
	}
}


v4版本

Schedule.java

package cn.hncu.thread.schedule.v4;

public class Schedule {

	public static void main(String[] args) {
		MyRun r=new MyRun();
		Thread t1=new Thread(r);
		Thread t2=new Thread(r);
		t1.start();
		t2.start();
	}

}

MyRun.java

package cn.hncu.thread.schedule.v4;

public class MyRun implements Runnable{
	private boolean isWait=true;
	@Override
	public void run() {
		synchronized(this){
			for(int i=0;i<100;i+=2){
				if(i>50&&isWait){
					isWait=false;
					try {
						wait(); //会释放锁
					} catch (InterruptedException e) {
						System.out.println("被唤醒了....");
					}
				}
				System.out.print(i+" ");
			}
			System.out.println();
			notify();
		} //还锁
	}
	
}

一个线程跑到50就等待,另外一个线程开始跑



线程互斥加强(互斥锁)


★带互斥的共享栈

      多线程互斥共享“栈”资源

Client.java

package cn.hncu.thread.shareStack;

public class Client {
	
	public static void main(String[] args) {
		MyStack ms=new MyStack();
		PushThread push=new PushThread(ms);
		PopThread pop=new PopThread(ms);
		push.start();
		pop.start();
	}
}

MyStack.java

package cn.hncu.thread.shareStack;

public class MyStack {
	int idx=0;
	char data[]=new char[6];
	public void push(char ch){
		//同步块  对象直接指定
		synchronized(this){ //用this当对象锁
			data[idx++]=ch;
			System.out.println("push :"+ch);
			this.notify();
		}
	}
	//同步方法: 对象锁是该方法的拥有者  ---静态方法是类,非静态方法是this对象
	public synchronized char pop(){ //this对象锁
		if(idx<1){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("pop :"+data[--idx]);
		return data[idx];
	}
}

PushThread.java

package cn.hncu.thread.shareStack;

public class PushThread extends Thread{
	private MyStack stack;
	public PushThread(MyStack stack) {
		this.stack=stack;
	}
	@Override
	public void run() {
		for(int i=65;i<70;i++){
			stack.push((char) i);
		}
	}
	
}

PopThread.java

package cn.hncu.thread.shareStack;

public class PopThread extends Thread{
	private MyStack stack;
	public PopThread(MyStack stack) {
		this.stack=stack;
	}
	@Override
	public void run() {
		for(int i=65;i<70;i++){
			stack.pop();
		}
	}
	
}

★多窗口卖票

      多线程互斥共享“基本数据类型数据”资源

版本一

TicketSale.java

package cn.hncu.thread.ticket.v1;

public class TicketSale {

	public static void main(String[] args) {
		//开四个窗口 让它们都开始卖票(启动线程)
		TicketWindow tw=new TicketWindow("窗口 ");
		
		Thread t1=new Thread(tw);
		Thread t2=new Thread(tw);
		Thread t3=new Thread(tw);
		Thread t4=new Thread(tw);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

TicketWindow.java

package cn.hncu.thread.ticket.v1;

public class TicketWindow implements Runnable {
	private Integer num = 200; // 共享变量(基本数据类型的数据) 不能当对象锁---因为他不是对象
	private Object obj = new Object();// 可以新建一个与基本数据类型共享变量平行的对象,来替代它当锁
	private String name;

	public TicketWindow(String name) {
		this.name = name;
	}

	@Override
	public void run() {
		synchronized (obj) { // 拿锁--对象锁
		// synchronized(this){ //直接用this作对象锁也是可以的----非静态变量的对象锁是可以用this替代
			while (true) {
				if (num> 0) {
					System.out.println(name +": " + num);
					num--;
				}else{
					break;
				}
			}
		}//解锁---还锁
	}
}
//非静态变量要当对象锁时,直接用this代替(不需要再另外造对象),无论该变量是否为对象

版本二

TicketSale.java

package cn.hncu.thread.ticket.v2;

public class TicketSale {

	public static void main(String[] args) {
		//开四个窗口 让它们都开始卖票(启动线程)
		
		Thread t1=new Thread(new TicketWindow("窗口1 "));
		Thread t2=new Thread(new TicketWindow("窗口2 "));
		Thread t3=new Thread(new TicketWindow("窗口3 "));
		Thread t4=new Thread(new TicketWindow("窗口4 "));
		t2.start();
		t1.start();
		t4.start();
		t3.start();
	}

}


TicketWindow.java

package cn.hncu.thread.ticket.v2;

public class TicketWindow implements Runnable {
	private static Integer num = 200; // 共享变量(基本数据类型的数据) 不能当对象锁---因为他不是对象
	private static Object obj = new Object();// 可以新建一个与基本数据类型共享变量平行的对象,来替代它当锁
	private String name;

	public TicketWindow(String name) {
		this.name = name;
	}

	@Override
	public void run() {
		while(true){
			synchronized (obj) {//※静态变量的对象锁是不能用this来代替的
				if (num > 0) {
					System.out.println(name + ":" + num);
					num--;
				} else {
					break;
				}
			}
		}
	}
}

两个版本一个用了非静态变量作锁,一个用了静态变量作锁,两者还是有差别的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值