1, 线程间通讯。其实就是多个线程在操作同一个资源, 但是操作的动作不同。
class Res {private String name;private String sex;private boolean flag = false;public synchronized void set(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 out() {if(!flag)try{this.wait();}catch(Exception e){}System.out.println(name+"........"+sex);flag = false;this.notify();}}
//输入输出在两个不同的run方法中操作。但应保持同步,就需要一个共有的锁。(即资源对象锁)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.out();}}}class InputOutputDemo {public static void main(String[] args) {Res r = new Res();new Thread(new Input(r)).start();new Thread(new Output(r)).start();
}
}wait();notify();notifyAll(); 都是用在同步中。因为要对持有监视器(锁)的线程操作, 只有同步才具有锁。
操作线程的方法定义在 Object 类中,因为这些方法在操作同步线程时,都必须要标识它们所操作线程持有的锁,只有同一个锁上的被等待线程可以被同一个锁上的 notify 唤醒,不可以对不同锁中的线程进行唤醒。而锁可以是任意对象,所以可以被任意对象调用的方法定义在 Object 类中。2, 生产者消费者问题。class Resource {private String name;private int count = 1;private boolean flag = false;// t1 t2public synchronized void set(String name) {while(flag)try{this.wait();}catch(Exception e){} //t1(放弃资格) t2(获取资格)this.name = name+"--"+count++;System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);flag = true;this.notifyAll();}// t3 t4public synchronized void out() {while(!flag)try{this.wait();}catch(Exception e){} //t3(放弃资格) t4(放弃资格)System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);flag = false;this.notifyAll();}}class Producer implements Runnable {private Resource res;Producer(Resource res) {this.res = res;}public void run() {while(true) {res.set("+商品+");}}}class Consumer implements Runnable {private Resource res;Consumer(Resource res) {this.res = res;}public void run() {while(true) {res.out();}}}定义 while 判断标记,原因:让唤醒的线程再一次判断标记。
定义 notifyAll ,原因:需要唤醒对方线程,只有 notify ,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。问题:notifyAll不仅唤醒了对方线程,也唤醒了本方线程来竞争资源,而我们的目的是只须唤醒对方线程即可。
JDK1.5 中提供了多线程升级解决方案。将同步 synchronized 替换成现实 Lock 操作。将 Object 中的 wait,notify,notifyAll, 替换成了 Condition 对象。该对象可以通过 Lock 锁进行获取。此时需要 import java.util.concurrent.locks.* ;
class Resource {private String name;private int count = 1;private boolean flag = false;private Lock lock = new ReentrantLock();private Condition condition_pro = lock.newCondition();private Condition condition_con = lock.newCondition();public void set(String name)throws InterruptedException {lock.lock();try {while(flag)condition_pro.await();this.name = name+"--"+count++;System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);flag = true;condition_con.signalAll(); //只唤醒对方,使性能更优,正是1.5这个新特性的好处}finally {lock.unlock(); //释放锁的动作一定要执行。}}public void out()throws InterruptedException {lock.lock();try {while(!flag)condition_con.await();System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);flag = false;condition_pro.signalAll();}finally {lock.unlock();}}}class Producer implements Runnable {private Resource res;Producer(Resource res) {this.res = res;}public void run() {while(true)try { res.set("+商品+"); } catch (InterruptedException e) { }}}class Consumer implements Runnable {private Resource res;Consumer(Resource res) {this.res = res;}public void run() {while(true)try { res.out(); } catch (InterruptedException e) { }}}
3, 停止线程。
1)定义循环结束标记。
stop 方法已经过时。停止线程的方法只有一种, run 方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让 run 方法结束,也就是线程结束。
2) interrupt( 中断)方法。特殊情况:当线程处于冻结状态。就不会读取到标记,那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread 类提供该方法 interrupt();
class StopThread implements Runnable {private boolean flag =true;public synchronnized void run() {while(flag) {
//t1,t2两个线程死到这,无法结束。
try{wait();}catch{ Thread.currentThread().getName()+"....exception"; }System.out.println(Thread.currentThread().getName()+"....run");}}public void changeFlag() {flag = false;}}class StopThreadDemo {public static void main(String[] args) {StopThread st = new StopThread();Thread t1 = new Thread(st);Thread t2 = new Thread(st);
//在主线程中定义t1,t2为守护线程,则 t1,t2 守护主线程,依赖于主线程。// t1.setDaemon(true);// t2.setDaemon(true);t1.start();t2.start();int num = 0;while(true) {if(num++ == 60) {st.changeFlag();
//中断线程,强制清除线程的冻结状态,让该线程恢复到运行状态,使之读取循环结束标记来结束线程。t1.interrupt();t2.interrupt();break;}System.out.println(Thread.currentThread().getName()+"......."+num);}}}
4, 线程中的其他方法:
1)线程的 setDaemon()方法。守护线程(用户线程)。 t1.setDaemon(true); 希腊守护神。
如上述3的代码中,t1,t2为守护线程,守护主线程,主线程挂了,这个守护线程也挂掉。
2)线程的 join()方法。
当 A 线程执行到 B 线程的 .join() 方法时, A 就会等待。等 B 线程都执行完, A 才会执行。 join 可以用来临时加入线程执行。
3) t1.setPriority(Thread.MAX_PRIORITY) ;设置线程优先级,默认 5 ,最大 10 ,最小 1 。
4) Thread.yield(); // 暂停正在执行的线程, 释放执行权, 保证线程都可执行到 。5)toString(); //返回该线程的字符串表示形式,包括线程 名称、优先级和线程组。
class Demo implements Runnable {public void run() {for(int x=0; x<70; x++) {System.out.println(Thread.currentThread().toString()+"....."+x);Thread.yield(); //暂停当前正在执行的线程对象,释放执行权,并执行其他线程。}}}class JoinDemo {public static void main(String[] args) throws Exception {Demo d = new Demo();Thread t1 = new Thread(d);Thread t2 = new Thread(d);t1.start();t1.setPriority(Thread.MAX_PRIORITY); //设置t1线程的优先级为最大,即10。t2.start();t1.join(); //抢夺主线程的CPU的执行权。for(int x=0; x<80; x++) {System.out.println("main....."+x);}System.out.println("over");}}
5,多线程的实际开发应用:
1)多线程常用使用方式 ( 匿名内部类 ) 一:
new Thread() {public void run() {for(int x=0;x<100;x++) {System.out.println(Thread.currentThread().toString()+"......"+x);}}}.start();
2)多线程常用使用方式 ( 匿名内部类 ) 二:
Runnable r=newRunnable() {public void run() {
for(int x=0;x<100;x++) {System.out.println(Thread.currentThread().getName()+"......"+x);}}};newThread(r).start();
黑马程序员——10Java多线程2
最新推荐文章于 2016-01-02 23:55:42 发布