java----多线程

来源:互联网 发布:mac sierra好用吗 编辑:程序博客网 时间:2024/06/06 14:14
多线程
一、线程通信
疑问思考1wait()notify()notifyAll()用来操作线程,为什么定义在Object类中?
1.这些方法存在同步中,因为要对监视器()的线程操作,所以要使用在同步中,因为只有同步才有锁的概念。
2.使用这些方法时,必须要标识所属的同步的锁。只有同一个锁上的被等待线程,可以被同一个锁上的notify()唤醒,不可以对不同锁中的线程进行唤醒,也就是说,等待和唤醒必须是同一个锁。
3.锁可以是任意对象,所以任意对象调用的方法一定定义在Object类中。
疑问思考2:wait(),sleep()有什么区别?
wait():释放资源,释放锁。
sleep():释放资源,不释放锁。
线程间通信:其实就是多个线程在操作同一个资源,但是操作的动作不同。
class Res{String name;String sex;}class Input implements Runnable{private Res r;Input(Res r){this.r = r;}public void run(){int x = 0;while(true){synchronized(r){if(x==0){r.name = "mike";r.sex = "man";}else{r.name = "丽丽";r.sex = "女女女女女";}x = (x+1)%2;}}}}class Output implements Runnable{private Res r;Output(Res r){this.r = r;}public void run(){while(true){synchronized(r){System.out.println(r.name+"..."+r.sex);}}}}class Demo{public static void main(String []args){Res r = new Res();Input in = new Input(r);Output out = new Output(r);Thread t1 = new Thread(in);Thread t2 = new Thread(out);t1.start();t2.start();}}

发现:程序有待优化,程序在疯狂打印,而不是输入一个打印一个的效果。
优化:采用wait()和notify()控制输入和输出。
class Res{private String name;private String sex;private boolean flag = false;Res(){}public synchronized void set(String name,String sex){this.name = name;this.sex = sex;flag = true;this.notify();if(flag){try{this.wait();}catch(Exception e){}}}public synchronized void get(){System.out.println(name+"..."+sex);flag = false;this.notify();if(!flag){try{this.wait();}catch(Exception e){}}}}class Input implements Runnable{private Res r;Input(Res r){this.r = r;}public void run(){int x =0;while(true){if(x==0){r.set("mike","man");}else{r.set("丽丽","女女女女");}x = (x+1)%2;}}}class Output implements Runnable{private Res r;Output(Res r){this.r = r;}public void run(){while(true){r.get();}}}class Demo{public static void main(String []args){Res r = new Res();new Thread(new Input(r)).start();new Thread(new Output(r)).start();}}

需求:生产者与消费者
class Product{private String name;private int count;private boolean flag = false;Product(){}public synchronized void set(String name){if(flag){try{this.wait();}catch(Exception e){}}this.name = name+count++;System.out.println(Thread.currentThread().getName()+"生产------"+this.name);flag = true;this.notify();}public synchronized void get(){if(!flag){try{this.wait();}catch(Exception e){}}System.out.println(Thread.currentThread().getName()+"消费---------------"+this.name);flag= false;this.notify();}}class SC implements Runnable{private Product pd;SC(Product pd){this.pd = pd;}public void run(){while(true){pd.set("+商品+");}}}class XS implements Runnable{private Product pd;XS(Product pd){this.pd = pd;}public void run(){while(true){pd.get();}}}class Demo{public static void main(String []args){Product pd = new Product();SC sc = new SC(pd);XS xs = new XS(pd);Thread t1 = new Thread(sc);Thread t2 = new Thread(xs);t1.start();t2.start();}}

发现:只有一个生产和一个消费,想要多个线程同时执行,已提高效率。所以对程序改进。
class Product{private String name;private int count;private boolean flag = false;Product(){}public synchronized void set(String name){if(flag){try{this.wait();}catch(Exception e){}}this.name = name+count++;System.out.println(Thread.currentThread().getName()+"生产------"+this.name);flag = true;this.notify();}public synchronized void get(){if(!flag){try{this.wait();}catch(Exception e){}}System.out.println(Thread.currentThread().getName()+"消费---------------"+this.name);flag= false;this.notify();}}class SC implements Runnable{private Product pd;SC(Product pd){this.pd = pd;}public void run(){while(true){pd.set("+商品+");}}}class XS implements Runnable{private Product pd;XS(Product pd){this.pd = pd;}public void run(){while(true){pd.get();}}}class Demo{public static void main(String []args){Product pd = new Product();SC sc = new SC(pd);XS xs = new XS(pd);Thread t1 = new Thread(sc);Thread t2 = new Thread(sc);Thread t3 = new Thread(xs);Thread t4 = new Thread(xs);t1.start();t2.start();t3.start();t4.start();}}

问题分析:程序出现了上产两个,而消费一个的情况。t1执行完后,t2抢到运行资格但wait()了,这时t3执行完notify(),然后t1又抢到资格执行notify()t2醒来接着执行,所以就发生生产两个消费一个的情况。
解决思路:让每次wait()醒来的线程进行flag判断。因为if只判断一次,所以要换成while

问题分析:所有线程wait了。
解决思路:这时候,因为已经没有线程在运行了,都在冻结状态,所以使用notifyAll
class Product{private String name;private int count;private boolean flag = false;Product(){}public synchronized void set(String name){while(flag){try{this.wait();}catch(Exception e){}}this.name = name+count++;System.out.println(Thread.currentThread().getName()+"生产------"+this.name);flag = true;this.notifyAll();}public synchronized void get(){while(!flag){try{this.wait();}catch(Exception e){}}System.out.println(Thread.currentThread().getName()+"消费---------------"+this.name);flag= false;this.notifyAll();}}class SC implements Runnable{private Product pd;SC(Product pd){this.pd = pd;}public void run(){while(true){pd.set("+商品+");}}}class XS implements Runnable{private Product pd;XS(Product pd){this.pd = pd;}public void run(){while(true){pd.get();}}}class Demo{public static void main(String []args){Product pd = new Product();SC sc = new SC(pd);XS xs = new XS(pd);Thread t1 = new Thread(sc);Thread t2 = new Thread(sc);Thread t3 = new Thread(xs);Thread t4 = new Thread(xs);t1.start();t2.start();t3.start();t4.start();}}

疑问如何停止线程
1.定义循环结束标记。因为线程运行代码一般都是循环的,只要控制了循环即可。
2.使用interrupt();中断方法。该方法是结束线程的冻结状态,使线程回到运行状态中来。
stop();方法已经过时不再使用。
class Test implements Runnable{private boolean flag = true;//定义结束标记Test(){}spublic void run(){while(flag){//当条件不满足时,线程就结束了System.out.println("hahahahaha");}}public void setFlag(){flag = false;}}class Demo{public static void main(String []args){Test test = new Test();Thread t = new Thread(test);t.start();for(int x=0;x<100;x++){System.out.println("main"+"-----"+x);}test.setFlag();}}

class Test implements Runnable{private boolean flag = true;public synchronized void run(){try{this.wait();}catch(Exception e){}System.out.println("over");}}class Demo{public static void main(String []args){Test test = new Test();Thread t = new Thread(test);t.start();try{Thread.sleep(5000);}catch(Exception e){}t.interrupt();}}

特殊情况
class Test implements Runnable{private boolean flag = true;public synchronized void run(){while(flag){try{this.wait();}catch(InterruptedException e){System.out.println("throw Exception");}}System.out.println("run");}public void change(){flag = false;}}class Demo{public static void main(String []args){Test test = new Test();Thread t = new Thread(test);t.start();try{Thread.sleep(2000);}catch(Exception e){}test.change();}}

发现:如果线程冻结了,即使改变了标记,也停止不了线程。
解决办法:把线程中断,从冻结状态变成运行状态,再对标记进行改变,就能停掉线程。
class Test implements Runnable{private boolean flag = true;public synchronized void run(){while(flag){try{this.wait();}catch(InterruptedException e){System.out.println("throw Exception");change();}}System.out.println("run");}public void change(){flag = false;}}class Demo{public static void main(String []args){Test test = new Test();Thread t = new Thread(test);t.start();try{Thread.sleep(2000);}catch(Exception e){}t.interrupt();}}

总结:当没有指定的方式让冻结的线程恢复到运行状态时,这时就需要对冻结状态进行清除。强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。Thread类中提供了该方法:interrupt();
守护线程setDaemon(boolean on);将线程标记为守护线程或用户线程。需要在启动线程前调用,也就是start();前。
特点:后台线程开启后和前台线程共同抢夺CPU执行权运行。当前台线程全部结束,后台线程会自动结束。
例:
class Demo{public static void main(String []args){Thread t = new Thread(){public synchronized void run(){try{this.wait();}catch(Exception e){}}};t.setDaemon(true);t.start();for(int x=0;x<60;x++){System.out.println(x);}}}

分析:虽然开启的线程是冻结状态,但是由于是守护线程,所以当主线程结束,守护线程也自动结束了。
join():等待该线程终止。
特点:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程执行完,A才会执行,join可以用来临时加入线程执行。
class Demo implements Runnable{public void run(){for(int x=0;x<70;x++){System.out.println(Thread.currentThread().getName()+"..."+x);}}}class JoinDemo{public static void main(String []args){Demo d = new Demo();Thread t1 = new Thread(d);Thread t2 = new Thread(d);t1.start();try{t1.join();}catch(Exception e){}t2.start();for(int x=0;x<80;x++){System.out.println("main"+"..."+x);}System.out.println("over");}}
toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

名称:Thread-1。
优先级:5。
线程组:main。
setPriority(int newPriority):更改线程的优先级。默认优先级为5,总共10级,1~10
MAX_PRIORITY:线程可以具有的最高优先级。
MIN_PRIORITY:线程可以具有的最低优先级。
NORM_PRIORITY:分配给线程的默认优先级。
yield():暂停当前正在执行的线程对象,并执行其他线程。让线程都有机会执行。