黑马程序员-多线程(二)

来源:互联网 发布:arttemplate.js api 编辑:程序博客网 时间:2024/05/27 20:11

多线程之间的通信:

其实就是多个线程在操作同一个资源,但是操作的动作不同

wait();  notify();  notifyAll();操作,如下代码:

class Res<span style="color:#3f7f5f;"> //线程要操作的资源类</span>{private boolean flag=false;private String name;private String sex;public synchronized void setvalue(String name,String sex) {if(flag)try{this.wait();}catch(Exception e){}this.name = name;this.sex=sex;flag=true;this.notify();}public synchronized void show(){if(!flag)try{this.wait();}catch(Exception e){}System.out.println(name+"====="+sex);flag=false;this.notify();}}class Input implements Runnable{Res res;public Input(Res res) {this.res=res;}public void run(){int x=0;while (true) {if(x==0)res.setvalue("张三","男");elseres.setvalue("莉莉","女");x=(x+1)%2;}}}class Output implements Runnable{Res res;public Output(Res res) {this.res=res;}public void run(){while(true){res.show();}}}public class InputOutputDemo1 {public static void main(String[] args) {Res res=new Res();new Thread(new Input(res)).start();new Thread(new Output(res)).start();}}<span style="color:#3f7f5f;">/* wait(); notify(); notifyAll(); 都使用在同步中,因为要持有监视器(锁)的线程操作. 所以要使用在同步中,因为只有同步才有锁. 为什么这些操作线程的方法要定义在Object类中呢? 因为这些方法在操作同步中的线程时,都必须要标识他们所操作线程持有的锁 只有同一个锁上的被等待线程才可以被同一个锁上的notify唤醒. 不可以对不同锁中的线程进行唤醒. 也就是说,等待和唤醒必须是同一个锁 而锁可以是任意对象,所以可以被任意对象调用的方法要定义在Object类中.*/</span>

生产者消费者示例:

生产者消费者示例一:

如下代码:

class Resource{private String name;private int count=0;private boolean flag;public synchronized void setvalue(String name) {while(flag)try{this.wait();}catch(Exception e){}this.name = name+"编号:"+count++;flag=true;System.out.println(Thread.currentThread().getName()+"生产者======"+this.name);this.notifyAll();}public synchronized void show(){while(!flag)try{this.wait();}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"消费者===="+name);flag=false;this.notifyAll();}}class Producer implements Runnable{Resource res=new Resource();public Producer(Resource res) {this.res=res;}public void run(){int x=0;while(true){res.setvalue("产品");x=(x+1)%2;}}}class Consumer implements Runnable{Resource res=new Resource();public Consumer(Resource res) {this.res=res;}public void run() {while(true){res.show();}}}public class ProducerConsumerDemo {public static void main(String[] args) {Resource res=new Resource();new Thread(new Producer(res)).start();new Thread(new Consumer(res)).start();new Thread(new Producer(res)).start();new Thread(new Consumer(res)).start();}}

通过分析发现:

这段代码一直在做着while......notifyAll()的动作,每次都会唤醒所有的线程,造成资源浪费,所以这种方法不推荐使用.下面介绍一直新的方式:JDK1.5的新特性

 

JDK1.5中提供了多线程升级解决方案,

将同步synchronized替换成了Lock操作

将Object中的wait(),notify(),notifyAll();替换了Condition对象

该对象可以通过lock锁进行获取

该示例中实现了本方只唤醒对方的操作

如下代码:

class Resource1{private String name;private int count=0;private boolean flag;private Lock lock=new ReentrantLock();private Condition condition_pro=lock.newCondition();private Condition condition_con=lock.newCondition();public void setvalue(String name) throws InterruptedException {lock.lock();try {while(flag)condition_pro.await();this.name = name+"编号:"+count++;flag=true;System.out.println(Thread.currentThread().getName()+"生产者======"+this.name);condition_con.signal();} finally {lock.unlock();//一定会释放锁}}public void show() throws InterruptedException{lock.lock();try {while(!flag)condition_con.await();System.out.println(Thread.currentThread().getName()+"消费者===="+name);flag=false;condition_pro.signal();} finally {lock.unlock();//一定会释放锁}}}class Producer1 implements Runnable{Resource1 res;public Producer1(Resource1 res) {this.res=res;}public void run(){int x=0;while(true){try {res.setvalue("产品");} catch (InterruptedException e) {e.printStackTrace();}x=(x+1)%2;}}}class Consumer1 implements Runnable{Resource1 res;public Consumer1(Resource1 res) {this.res=res;}public void run() {while(true){try {res.show();} catch (InterruptedException e) {e.printStackTrace();}}}}public class LockDemo {public static void main(String[] args) {Resource1 res=new Resource1();new Thread(new Producer1(res)).start();new Thread(new Consumer1(res)).start();new Thread(new Producer1(res)).start();new Thread(new Consumer1(res)).start();}}

停止线程:

 stop方法已经过时

 那么该如何停止线程呢?

 只有一种,run方法结束

 开启多线程运行,运行的代码通常都是循环结构的,所以只要控制住循环就能让run方法结束,也就是线程结束

如下代码:

class StopThread implements Runnable{private boolean flag=true;public void run() {while(flag){System.out.println("Thread Run!");}}public void setFlag(){flag=false;}}public class StopThreadDemo1 {public static void main(String[] args) {StopThread st=new StopThread();Thread t1=new Thread(st);Thread t2=new Thread(st);t1.start();t2.start();int x=0;while (true) {if(x++ ==100){st.setFlag();break;}System.out.println("main...........");}System.out.println("over");}}

通过标记来完成对run方法中的循环进行控制,当主函数中的循环跑了100次后设置线程的flag标记为false;

 

以下还有一种特殊情况是没办法结束的:

当线程处于wait()冻结状态

就不会读取到flag标记,就无法结束循环

代码如下:

class StopThread implements Runnable{private boolean flag=true;public synchronized void run() {while(flag){try {this.wait();} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName()+":异常了....");}System.out.println(Thread.currentThread().getName()+":Run!");}}public void setFlag(){flag=false;}}public class StopThreadDemo1 {public static void main(String[] args) {StopThread st=new StopThread();Thread t1=new Thread(st);Thread t2=new Thread(st);t1.start();t2.start();int x=0;while (true) {if(x++ ==100){st.setFlag();break;}System.out.println("main..........."+x);}System.out.println("over");}}

当没有指定的方式让冻结的线程恢复到运行状态时,这时需要清除线程的冻结状态

强制让线程回复到运行状态中来,这样就可以操作标记让线程结束

Thread类中提供了该方法 interrupt();

代码如下:

class StopThread implements Runnable{private boolean flag=true;public synchronized void run() {while(flag){try {this.wait();} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName()+":异常了....");flag=false;}System.out.println(Thread.currentThread().getName()+":Run!");}System.out.println(Thread.currentThread().getName()+":over!");}public void setFlag(){flag=false;}}public class StopThreadDemo1 {public static void main(String[] args) {StopThread st=new StopThread();Thread t1=new Thread(st);Thread t2=new Thread(st);t1.start();t2.start();int x=0;while (true) {if(x++ ==100){st.setFlag();t1.interrupt();t2.interrupt();break;}System.out.println("main..........."+x);}System.out.println("over");}}

守护线程:

setDaemon(boolean on)

也称为后台线程,如果当前台线程都结束后,后台线程自动结束,jvm退出.

守护线程必须在线程启动之前调用,也就是说要在线程启动之前设置是否是守护线程

比如 圣斗士-星矢中的圣斗士就是围着雅典娜转,雅典娜一挂圣斗士也就没啥事了,就没有存在的意义了

 

如下代码:

代码中主函数代码结束后守护线程也自动结束

class Thread1 implements Runnable{public void run(){while(true){System.out.println("Thread1");}}}class Thread2 implements Runnable{public void run(){while(true){System.out.println("Thread2");}}}public class GuardianDemo {public static void main(String[] args) {Thread1 t1=new Thread1();Thread2 t2=new Thread2();Thread t3=new Thread(t1);Thread t4=new Thread(t2);t3.setDaemon(true);t4.setDaemon(true);t3.start();t4.start();for(int x=0;x<=100;x++){System.out.println("main........");}}}

当主函数中的for循环完成后,所有线程都结束了,jvm退出,原本在Thread1和Thread2中的都是无限循环的,设置了守护线程后当主函数执行完成后自动退出....


Join:

等待线程结束,等待join的那个线程结束主线程才会继续,也就是说,如果A线程碰到了B线程的join,那么A线程会等待,等待到B线程执行完毕才会继续执行,如下代码:

class Join implements Runnable{public void run(){for(int x=0;x<100;x++){System.out.println("Join......."+x);}}}class Join1 implements Runnable{public void run(){for(int x=0;x<100;x++){System.out.println("Join1......."+x);}}}public class JoinDemo {public static void main(String[] args) throws InterruptedException {Join j1=new Join();Join1 j2=new Join1();Thread t1 =new Thread(j1);Thread t2 =new Thread(j2);t1.start();t1.join();t2.start();//t1.join();for(int x=0;x<100;x++){System.out.println("JoinDemo......."+x);}}}

通过上面的代码发现只有在t1线程执行完毕后t2和主线程交替执行,如果t1.join放在t2.start()后面的话,t1和t2线程会交替执行,直到t1执行完毕后主线程才会执行,如果这时t2线程还没有结束的话,主线程会和t2交替执行.


优先级&线程名称&线程组:

toString:覆盖了Object类中的toString方法,可以打印出线程名称和优先级及线程组

线程组:谁开启的线程就属于哪个组

优先级:优先级高的线程抢CPU的频率会高一点,所有线程的默认优先级是5

优先级可以通过setPriority来改变,跨度最大的三个优先级如 1  5  10,这三个优先级有专用的常量值,MAX_PRIORITY:10   MIN_PRIORITY:1   NORM_PRIORITY:5

 

yield:暂停当前正在执行的线程对象,并执行其他线程。能够稍微减缓线程的执行,让其他的线程更能有机会抢到CPU的执行权


0 0
原创粉丝点击