java学习之多线程(二)
线程间通讯:
其实就是多个线程在操作同一个资源,但是操作的动作不同。
案例:对姓名性别的设置与读取。
代码中标志位可以是boolean flag,也可以是int x,x=(x+1)%2。
加了同步还出错,于是想同步前提:一是2个以上线程是否同步代码(即代码是对同一个资源的操作);二是同一个锁。
wait:
notify():
notifyAll():
都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步线程时,都必须要标识它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒,不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
class Res{ private String name; private String sex; private boolean flag = false; public synchronized void set(String name, String sex) { while(flag) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } this.name = name; this.sex = sex; flag = true; this.notifyAll(); } public synchronized void out(){ while(flag) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name+"..."+sex); flag = false; this.notifyAll(); } } //对资源进行设置操作 class Input implements Runnable{ Res r; public Input(Res r) { this.r = r; } @Override public void run() { int x = 0; if(x==0){ r.set("mike","man"); }else{ r.set("莉莉","女"); } x = (x+1)%2; } } //对资源进行读取操作 class OutPut implements Runnable{ Res r; public OutPut(Res r) { this.r = r; } @Override public void run() { while (true) r.out(); } } //测试 public class Test{ public static void main(String[] args){ Res r = new Res(); Thread t1 = new Thread(new Input(r)); Thread t2 = new Thread(new OutPut(r)); t1.start(); t2.start(); } }
线程间通讯--生产者消费者:
jdk1.5 中提供了多线程升级解决方案,将同步synchronized替换成显示Lock操作,将Object中的wait,notify,notifyAll替换了condition对象,该对象可以对Lock锁进行替换。
该示例中,实现了本方只唤醒对方操作。并且可以执行多个设置和读取操作
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Res{ private String name; private String sex; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition_input = lock.newCondition(); private Condition condition_output = lock.newCondition(); public void set(String name, String sex) { lock.lock(); try { while(flag) try { condition_input.await(); } catch (InterruptedException e) { e.printStackTrace(); } this.name = name; this.sex = sex; flag = true; condition_output.signal(); }finally { lock.unlock(); } } public void out(){ lock.lock(); try { while(flag) try { condition_output.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name+"..."+sex); flag = false; condition_input.signal(); }finally { lock.unlock(); } } } //对资源进行设置操作 class Input implements Runnable{ Res r; public Input(Res r) { this.r = r; } @Override public void run() { int x = 0; if(x==0){ r.set("mike","man"); }else{ r.set("莉莉","女"); } x = (x+1)%2; } } //对资源进行读取操作 class OutPut implements Runnable{ Res r; public OutPut(Res r) { this.r = r; } @Override public void run() { while (true) r.out(); } } //测试 public class Test{ public static void main(String[] args){ Res r = new Res(); Thread t1 = new Thread(new Input(r)); Thread t2 = new Thread(new OutPut(r)); t1.start(); t2.start(); } }
--------------------------------------------------------------------------------
多线程:停止线程:
1.定义循环结束标记
因为线程运行代码一般都是循环,只要控制了循环即可
2.使用interrupt(中断)方法
该方法是结束线程的冻结状态,使线程回到运行状态中来
注:stop方法已经过时不再使用。
stop方法已经过时,如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
显而易见,可以想到用标记来停止线程,但是特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清楚,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供该方法interrupt();
--------------------------------------------------------------------------------
多线程:守护线程:(类似后台线程):当正在运行的线程都是守护线程时,java虚拟机退出。该方法必须在启动线程前调用。看api
看见的线程都是前台线程,而后台线程的特点是:当所有的前台线程都结束后后台线程也会结束。
多线程:Jion方法:等待该线程终止。
特点:当a线程执行到了b线程的.join()方法时,a就会等待,等b线程都执行完,a才会执行。jion可以用来临时加入线程执行。
优先级&yield方法
yield:暂停当前正在执行的线程对象,并执行其他线程。
在开发中如何使用多线程--使用匿名内部类达到并发效果
public static void main(String[] args){ Runnable r = new Runnable() { @Override public void run() { for (int i=0;i<60;i++) System.out.println(Thread.currentThread().getName()+"..."+i); } }; new Thread(r).start(); }
}