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

来源:互联网 发布:卡通农场数据恢复 编辑:程序博客网 时间:2024/04/30 00:48

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;}@Overridepublic 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;}@Overridepublic 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.IllegalThreadStateExceptiont2.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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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线程一直waitobj.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;@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic void run() {while(true){synchronized (obj) {//※静态变量的对象锁是不能用this来代替的if (num > 0) {System.out.println(name + ":" + num);num--;} else {break;}}}}}

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


原创粉丝点击