多线程一 几个方法区别
sleep() 和 wait() 有什么区别? 搞线程的最爱
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非(a)“醒来”的线程具有更高的优先级 (b)正在运行的线程因为其它原因而阻塞。
wait()是线程交互时,如果线程对一个同步对象(方法)x 发出一个wait()调用,该线程会暂停执行,被调对象(方法)进入等待状态,直到被唤醒或等待时间到。
Wait时别的线程可以访问锁定对象(调用wait,锁就撒手);
调用wait方法的时候必需锁定该对象;
Object提供的方法
Sleep时别的线程也不可以访问锁定对象(睡着也抱着锁);
Thread提供的方法
请参考下面2个例子就全明白了......
同步:
a.每个对象只有一把锁
b.一个线程访问同步方法时候,别的线程可以访问该对象的其他非同步的方法,而且也可以影响同步方法内部的变量。
例1:
public class TT implements Runnable {int b = 100;public synchronized void m1() throws Exception{b = 1000;Thread.sleep(1000);System.out.println("b = " + b);}public synchronized void m2() throws Exception {Thread.sleep(3000);b = 2000;}public void run() {try {m1();} catch(Exception e) {e.printStackTrace();}}public static void main(String[] args) throws Exception {TT tt = new TT();Thread t = new Thread(tt);t.start();tt.m2();System.out.println(tt.b);}}===输出结果有2中可能====如果主线程锁定当前对象,输出结果为:2000b = 1000如果子线程锁定当前对象,输出结果为:1000b = 1000例2:范例名称:生产者--消费者问题
遇到互斥的问题时候如何解决得呢?
答:将互斥的2个操作放到同一个类的2个方法中,然后让这2个方法都加上synchronized关键字修饰
/* * 源文件名称:SyncTest.java
*要 点:
*1. 共享数据的不一致性/临界资源的保护
*2. Java对象锁的概念
*3. synchronized关键字/wait()及notify()方法
*/
package com.wlh;public class ProduceConsumer { public static void main(String args[]){ SyncStack stack = new SyncStack(); Runnable p=new Producer(stack); Runnable c = new Consumer(stack); Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } } /** * 支持多线程同步操作的堆栈的实现 * 因为只有一个线程能够锁定当前对象,而同步方法的执行前先锁定当前对象, * 所以同一时刻,同步方法push和pop只能有一个在执行 * @author wulihai */class SyncStack{ private int index = 0; private char []data = new char[6]; public synchronized void push(char c){ if(index == data.length){ try{ this.wait(); }catch(InterruptedException e){} } this.notify(); data[index] = c; index++; } public synchronized char pop(){ if(index ==0){ try{ this.wait(); }catch(InterruptedException e){} } this.notify(); index--; return data[index]; } } class Producer implements Runnable{ SyncStack stack; public Producer(SyncStack s){ stack = s; } public void run(){ for(int i=0; i<20; i++){ char c =(char)(Math.random()*26+'A');// stack.push(c); System.out.println("produced:"+c); try{ Thread.sleep((int)(Math.random()*1000)); //随机休息,这样看起来生产和消费的产品个数都是随机的 }catch(InterruptedException e){ } } } } class Consumer implements Runnable{ SyncStack stack; public Consumer(SyncStack s){ stack = s; } public void run(){ for(int i=0;i<20;i++){ char c = stack.pop(); System.out.println("消费:"+c); try{ Thread.sleep((int)(Math.random()*1000));//随机休息,这样看起来生产和消费的产品个数都是随机的 }catch(InterruptedException e){ } } } } 死锁:当一个或多个进程等待系统资源,而系统资源又同时被此进程本身或者其它进程占用
例:结果2个线程谁都不打印输出数据
package com.wlh;public class DeadLock extends Thread {int flag=0;static Object o1=new Object();static Object o2=new Object();public DeadLock(int flag){this.flag=flag;}@Overridepublic void run() {if(this.flag==1){synchronized(o1){System.out.println(Thread.currentThread().getName()+"锁定对象o1");try {Thread.sleep(1000);//让另一个线程能进入另一块区域,锁定对象o2} catch (InterruptedException e) {e.printStackTrace();}synchronized(o2){System.out.print("this.flag="+this.flag);}}}if(this.flag==2){synchronized(o2){System.out.println(Thread.currentThread().getName()+"锁定对象o2");try {Thread.sleep(1000);//让另一个线程能进入另一块区域,锁定对象o1} catch (InterruptedException e) {e.printStackTrace();}synchronized(o1){System.out.print("this.flag="+this.flag);}}}}public static void main(String []args){DeadLock d1=new DeadLock(1);DeadLock d2=new DeadLock(2);d1.start();d2.start();}}Join方法:将某个子线程合并到主线程,即等子线程全部运行全部执行完之后才执行主线程
例1:
package com.wlh;public class TestJoin { public static void main(String[] args) { MyThread2 t1 = new MyThread2("子线程"); t1.start(); /* try { t1.join(); } catch (InterruptedException e) {}*/ for(int i=1;i<=10;i++){ try {Thread.sleep(1000);//当前线程休息1000秒System.out.println("i am main thread");} catch (InterruptedException e) {e.printStackTrace();} } }}class MyThread2 extends Thread { MyThread2(String s){ super(s); } public void run(){ for(int i =1;i<=10;i++){ System.out.println("i am "+getName()); try { sleep(1000);//当前线程休息1000秒 } catch (InterruptedException e) { return; } } }}备注:子线程和主线程交替执行
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
i am 子线程
i am main thread
例2:在 t1.start()子线程就绪;之后添加t1.join(),则等t1线程执行完之后才执行主线程
package com.wlh;public class TestJoin { public static void main(String[] args) { MyThread2 t1 = new MyThread2("子线程"); t1.start(); try { t1.join(); } catch (InterruptedException e) {} for(int i=1;i<=10;i++){ try {Thread.sleep(1000);//当前线程休息1000秒System.out.println("i am main thread");} catch (InterruptedException e) {e.printStackTrace();} } }}class MyThread2 extends Thread { MyThread2(String s){ super(s); } public void run(){ for(int i =1;i<=10;i++){ System.out.println("i am "+getName()); try { sleep(1000);//当前线程休息1000秒 } catch (InterruptedException e) { return; } } }}输出结果:
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am 子线程
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
Yeild方法:当前线程让出CPU的时间给其他线程执行一会。注意:是让出一会儿,待会又回来了。。。
package com.wlh;public class TestYield { public static void main(String[] args) { MyThread3 t1 = new MyThread3("t1"); MyThread3 t2 = new MyThread3("t2"); t1.start(); t2.start(); }}class MyThread3 extends Thread { MyThread3(String s){super(s);} public void run(){ for(int i =1;i<=100;i++){ System.out.println(getName()+": "+i); if(i%10==0){ yield(); } } }}输出结果:只要一个线程执行到10的整数倍,必然让出CPU的时间给其他线程执行一会
t1: 1
t1: 2
t1: 3
t1: 4
t1: 5
t1: 6
t1: 7
t1: 8
t1: 9
t1: 10
t2: 1
t2: 2
t2: 3
t2: 4
t2: 5
t2: 6
t2: 7
t2: 8
t2: 9
t2: 10
t1: 11
t1: 12
t1: 13
t1: 14
t1: 15
t1: 16
t1: 17
t1: 18
t1: 19
t1: 20
t2: 11
t2: 12
t2: 13
t2: 14
t2: 15
...........
..............
...................