一:写一个煤矿例子,一个线程运煤,一个拉煤;
day12-02-多线程(线程间通信-解决安全问题)
class Res{
private String name;
private String sex;
}
class Input implements Runnable{
Res r;
public Input(Res r){
this.r = r;
}
public void run(){
while(true){
Synchronized(r){
int x =0
if(x==0){
r.name = "abc";
r.sex = "man";
}else{
r.name="ddd";
r.sex="women";
}
x = (x+1)%2;
}
}
}
}
class Output implements Runnable{
Res r;
public Output(Res r){
this.r = r;
}
public void run(){
Synchronized(r){
System.out.println("Name="+r.name+".........Sex="+r.sex);
}
}
}
public class InputOutputDemo{
public static void main(String[] args){
Res r = new Res();
Input input= new Input(r);
Output output = new Output(r);
input.start();
output.start();
}
总结:这里面存在两个线程,拥有两个资源,如果需要同步需要在两个run中都加Synchronized,并且Synchronized锁对象只能为同一个资源,不能为this,可以为Input.class或Output.class或Res;才能正常锁住,不然都会存在问题;
二:day12-03-多线程(线程间通信-等待唤醒机制)
wait、notify、notifyAll
都使用在同步中,因为要对持有监视器(锁)的线程进行操作;
所以要使用在同步中,因为只有同步才具有锁;
为什么这些操作线程的方法都要定义在Object类中呢?
因为这些方法在操作同步时,都要标识它们所操作的线程只有锁;
只有同一个锁上被等待的线程,才能被同一个锁上的notify唤醒,不可能对不是同一个锁上的线程进行notify唤醒;也就是说,等待和唤醒都必须是同一个锁;
而锁也可以是任意对象,所以可以被任意对象调用的方法定义在Object类中;
三:day12-05-多线程(线程间通信-生产者消费)
考察点:
唤醒线程后,需要每次唤醒都校验下flag标记,改if为while;
用notify只能用作两个线程分别做两件事情,如果多于两个线程,同时做两件事情,用notify只能唤醒自己,需要更改notify为
notifyAll方法来处理,具体代码如下:
class Resoure{
private String name;
private int count = 1;
private boolean flag = false;
public Synchronized void set(String name){
while(flag){
try{ this.wait();}catch(Exception ex){}
this. name = name +"----name----"+count++;
System.out.println("生产者="+Thread.currentThread.getName()+"+++++++++++++"+count);
this.flag = true;
this.notifyAll();
}
}
public Synchronized void out(){
while(!flag){
try{this.wait();}catch(Exception ex){}
System.out.println("消费者="+Thread.currentThread.getName()+"-------------------------"+count);
this.flag = false;
this.notifyAll();
}
}
}
class Prodocer implements Runnable{
private Resoure res;
public Prodocer(Resoure res){
this.res = res;
}
public void run(){
while(true){
res.set("abc");
}
}
}
class Consumer implements Runnable{
private Resoure res;
public Consumer(Resoure res){
this.res= res;
}
public void run(){
while(true){
res.out();
}
}
}
public class ProdocerOrConsumerDemo{
public static void main(String[] args){
Resoure res = new Resoure();
Prodocer pro= new Prodocer(res);
Consumer con = new Consumer(res);
Thread thread1 = new Thread(pro);
Thread thread2 = new Thread(pro);
Thread thread3 = new Thread(con);
Thread thread4 = new Thread(con);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
四:day12-05-多线程(线程间通信-生产者消费) 启用JDK新特性 LOCK
class Resoure{
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 IntenException{
lock.Lock();
while(flag){
try{
condition_pro.await();
this. name = name +"----name----"+count++;
System.out.println("生产者="+Thread.currentThread.getName()+"+++++++++++++"+count);
this.flag = true;
condition_con.single();
}finally{lock.unLock();}
}
}
public void out()throws IntenException{
lock.Lock();
while(!flag){
try{
condition_con.await();
System.out.println("消费者="+Thread.currentThread.getName()+"-------------------------"+count);
this.flag = false;
condition_pro.single();
}finally{lock.unLock();}
}
}
}
class Prodocer implements Runnable{
private Resoure res;
public Prodocer(Resoure res){
this.res = res;
}
public void run(){
while(true){
try{
res.set("abc");
}catch(Exception ex){}
}
}
}
class Consumer implements Runnable{
private Resoure res;
public Consumer(Resoure res){
this.res= res;
}
public void run(){
while(true){
try{ res.out();}catch(Exception ex){}
}
}
}
public class ProdocerOrConsumerDemo{
public static void main(String[] args){
Resoure res = new Resoure();
Prodocer pro= new Prodocer(res);
Consumer con = new Consumer(res);
Thread thread1 = new Thread(pro);
Thread thread2 = new Thread(pro);
Thread thread3 = new Thread(con);
Thread thread4 = new Thread(con);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
//总结:single方法只唤醒对方线程,不会唤醒自己;通过Condition可以控制多个对象,Lock是线程中的显示方式实现,而同步是隐式方式实现。
五:day12-07-多线程(停止线程) ---interupte方法实现
stop方法已经过时,那么如何停止一个线程?
只有一种方法就是让run方法结束;
只要控制住循环,就可以让run方法结束,线程就停止了;
特殊情况:
当线程处于冻结状态时,可以采用以下代码:
while(flag){
try{
wait();
}catch(InterupteException ex){
//ex
flag = true;
}
}
当在其它地方调用了该线程的interupte方法后,线程会强制从冻结状态抛出interupteException,然后再回到运行状态;
六:day12-08-多线程(守护线程)
setDaemon(true),true为守护线程/后台线程,但前台线程/用户线程运行完毕,守护线程自然就结束;守护线程跟用户线程存在互相依赖的关系,可以通过isDaemon方法来判断是否是守护线程,setDaemon方法必须使用在线程开启方法前;
七:day12-09-多线程(Join方法)
join用来临时加入线程运行,例如A线程运行到B线程调用join方法后,A线程会等到B线程运行完毕后才运行;
八:day12-10-多线程(优先级yield方法)
优先级默认为5,一般为0-10,可以通过setPriority设置优先级;
Thread.yield、wait等都是运行是主线程,如果是其它线程对象调用yield方法,是用来暂停该线程,让其他线程进行争取CPU执行权;