您的位置:首页 > 职场人生

黑马程序员_JAVA笔记12——多线程间通讯

2013-09-01 16:48 281 查看
------- android培训java培训、期待与您交流! ----------
1、线程间通讯,其实就是多个线程在操作同一资源,但是操作动作不同
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)

{
synchroized(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)

{

synchroized(r)//此时的r,与上一个锁的r是同一个,表示这两个synchroized(r)是同一个锁

{

System.out.println("name"+r.name+
" sex"+r.sex
);
}

}
}

}
class InputOutputDemo
{
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();

}

}

知识理解:在多个synchroized(对象)中,只要这些对象是同一个对象,那么这些synchroized就表示是同一个锁。而括号中的对象,并不限定是谁的对象,只要唯一就可以。

wait() notify() notifyAll()用法:
都使用在同步中(锁中、监视器中),因为对持有监视器的线程操作。所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中,因为这些方法在操作同步中线程时,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁notify唤醒。不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任何对象,所以可以被任意对象调用的方法定义在Object类中。

class Res
{
String name;

String sex;

boolean flag = false;

}
class Input implements Runnable
{
private Res r ;
Input(Res r)

{
this.r = r;

}
public void run()

{
int x= 0;

while(true)

{

synchroized(r)

{

if(r.flag)

{

//wait()在定义时抛异常了,因此这里需要try catch 不能抛

try{r. wait();}catch(Exception e){}

}

if(x==0)

{

r.name = "mike";

r.sex = "man";

}

else

{

r.name = "丽丽";

r.sex = "女";

}

x = (x+1)%2;

r.flag=true;
r.notify();//默认唤醒第一个wait()的线程

}

}

}

}
class Output implements Runnable
{
private Res r;

Output(Res r)

{
this.r = r ;

}

public void run()

{
while(true)

{

synchroized(r)//此时的r,与上一个锁的r是同一个,表示这两个synchroized(r)是同一个锁

{

if(!r.flag)

{

try{r. wait();}catch(Exception e){}

}

System.out.println("name"+r.name+" sex"+r.sex);

r.flag = false;
r.notify();//默认唤醒第一个wait()的线程

}

}
}

}
class InputOutputDemo
{
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();

}

}

2、生产者消费者问题,有多个消费者多个生产者时必须用while循环,必须notifyAll.
原因:如下例子t1 t2 生产者 t3 t4 消费者,执行后:
明确一点:当线程在wait后,再次notify时,会继续执行wait语句后面的语句。
在这里,while 作用是在t1 t2都wait后,再次notify时,重新判断flag是否复合条件。同时,while的负作用就是会导致所有线程都进入wait状态,因此必须唤醒线程,用notifyAll();如果用notify()仅能唤醒一个线程,如果该线程不复合条件,那么又陷入全部线程等待的情况,因此用notifyAll();
class Resource
{
private String name;

private int count=1;

private boolean flag = false;

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 out()

{
while(!flag)

{
try{this.wait();}catch(Exception e){}
}

System.out.println(Thread.currentThread().getName()+"........消费者......."+this.name);

flag = true;

this.notifyAll();

}

}
class Producer implements Runnable
{
Resource res;

Producer(Resource res)

{
this.res = res;

}

public void run()

{
while(true)

{
res.set("producer");

}

}

}
class Consumer implements Runnable
{
Resource res;
Producer(Resource res)

{
this.res = res;

}

public void run()

{
while(true)

{
res.out();
}
}
}
class ProConDemo
{
public static void main(String[] args)

{
Resource res = new Resource();

Producer p = new Producer(res);

Consumer c = new Consumer(res);

Thread t1 = new Thread(p);

Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();

t2.start();

t3.start();

t4.start();

}

}

jdk1.5版本后,提供了多线程升级解决方案,将同步synchronized替换成了lock。
接口Lock,类ReentrantLock实现接口,Condition中await signal 代替wait notify
Lock中定义了方法:void lock() 获取锁 void unlock() 释放锁
Condition newCondition() 返回绑定到此Lock实例的Condition对象

Condition中定义了方法:await()等待 signal()唤醒一个线程 signalAll()唤醒所有线程
新特性:一个锁上可以有多个condition对象.(而一个synchronized只有一个wait notify)
如下红色代码:实现了pro唤醒con的操作,con唤醒了pro的操作。

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 = lock.newCondition();

// private Condition condition_pro = new lock.newCondition();

//private Condition condition_con = new lock.newCondition();

public synchronized void set(String name) throws InterruptedException

{
lock.lock();

try

{
while(flag)

{

condition.await();

//condition_pro.await();

}

this.name = name+"................."+count++;

System.out.println(Thread.currentThread().getName()+".....生产者......."+this.name);

flag = true;

condition.signalAll();

// condition_con.signal();

}
finally
{

lock.unlock();//释放锁的操作一定要执行

}

}

public synchronized void out() throws InterruptedException

{
lock.lock();
try

}

while(!flag)

{

condition.await();

//conditidon_con.await();

}

System.out.println(Thread.currentThread().getName()+"........消费者......."+this.name);

flag = true;

condition.signalAll();//唤醒所有线程
// condition_pro.signal();

}

finally

{
lock.unlock();

}

}

}
class Producer implements Runnable
{
Resource res;

Producer(Resource res)

{
this.res = res;

}

public void run()

{
while(true)

{
try//set(String name)抛异常了

{

res.set("producer");

}

catch(InterruptedException e)

{

}

}

}

}
class Consumer implements Runnable
{
Resource res;
Producer(Resource res)

{
this.res = res;

}

public void run()

{
while(true)

{
try//out()抛异常了

{

res.out();
}

catch(InterruptedException e)

{
}

}
}
}
class ProConDemo
{
public static void main(String[] args)

{
Resource res = new Resource();

Producer p = new Producer(res);

Consumer c = new Consumer(res);

Thread t1 = new Thread(p);

Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();

t2.start();

t3.start();

t4.start();

}

}

3、停止线程
stop方法已经过时,如何停止线程?只有一种方法,run方法结束。
开启多线程运行,运行代码通常是循环结构,因此只要控制住循环就可以让run方法结束,也就是线程结束
特殊情况:当线程处于冻结状态,就不会读取到标记,线程就不会结束。
当没有指定方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类中提供了该方法interrupt();
注意:使用了interrupt(),会抛异常InterruptedException 因此需要 try catch(InterruptedException e) 处理,在处理语句中操作标记,如下的flag=false,让线程回到运行状态。
class StopThread implements Runnable
{
private boolean flag = true;
public synchronized void run()

{
while(flag)

{
try

{

wait();

}

catch(InterruptedException e)

{
System.out.println(Thread.currentThread().getName()+".....Exception");
flag = false;

}

}

}

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.start();

t2.start();

while(true)

{
if(num++==60)

{
//st.changeFlag();

t1.interrupt();//强行中断t1冻结状态
break;

}

System.out.println(Thread.curentThread().getName()+".........."+num);

}

}
}

4、Thread类中的常见方法
一:poublic final void setDaemon(boolean on); 不抛异常
守护线程:将该线程标记为守护线程,当正在运行的线程都是守护线程时,JVM退出,该方法必须在启动线程前调用。
t1.setDaemon(true)//此时t1已成为守护线程,在t1.start()前调用

t2.setDaemon(true)//此时t2已成为守护线程,在t2.start()前调用

t1.start();

t2.start();
在上面例子中,若t1 t2为守护线程,则main线程结束时,t1 t2也结束了;如果t1 t2不是守护线程,在main线程结束后,t1 t2会毅然执行。

二:public final void join()
throw InterruptedException

class Demo implements Runnable
{
public void run()

{
for(int x=0;x<70;x++)
{
System.out.println(Thread.currendThread().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();

t1.join();//执行到这里时,主线程进入冻结状态,t1夺得执行权,t1执行,主线程等待t1结束后,再继续执行
t2.start();

// t1.join();若放在这里,主线程释放执行权并进入冻结状态,而这时t
1 t2都有执行资格,因此t1 t2交替执行,但是,当t1执行完毕后,主线程进入运行状态(不管t2是否执行完,若t2还没结束,则主线程与t2交替执行)。(这里,若t1 wait了,那么主线程也就over了,所以才有方法interrupt)

for(int x=0;x<80;x++)
{
System.out.println("main"+x);
}

System.out.println("over");
}
}

三:void toString(),翻译该线程的字符创表示形式,包括线程名称、优先级和线程组。
线程组:谁开启了线程谁就是线程组,如main开启了t1 t2,那么t1 t2属于main线程组。
优先级:代表抢夺资源的频率,谁优先级高,CPU就执行谁频繁一些。线程优先级默认是5级,包括主线程。
优先级范围:1——10级
static int MAX_PRIORITY:线程可以具有的最高优先级 10级

static int MIN_PRIORITY:线程可以具有的最低优先级 1级

static int NORM_PRIORITY:分配给线程的默认优先级 5级

设置优先级:

Demo d = new Demo();

Thread t1 = new Thread(d);

Thread t2 = new Thread(d);

t1.start();

t1.setPriority(Thread.MAX_PRIORITY);//表示t1执行频繁一些,但其他线程仍执行。

t2.start();

四:static void yield() 暂停当前正在执行的线程对象,并执行其他线程。

class Demo implements Runnable

{
public void run()

{
for(int x=0;x<70;x++)
{
System.out.println(Thread.currendThread().getName()+x);

Thread.yield();//表示执行到该语句的线程,临时释放执行权一小会儿,然后继续抢夺执行权执行。

}

}

}

class JoinDemo
{
public static void main(String[] args)

{
Demo d = new Demo();

Thread t1 = new Thread(d);

Thread t2 = new Thread(d);

t1.start();
t2.start();

for(int x=0;x<80;x++)
{
System.out.println("main"+x);
}

System.out.println("over");
}
}

5、实际开发过程中线程的写法
class ThreadTest
{
public static void main(String[] args)

{
//有多个循环时,需要循环同时执行,可采用匿名内部类方式,以下三个循环同时执行

new Thread()

{
public void run()
{
for(int i =0 ;i<199;i++)
{
System.out.println(Thread.currentThread().getName()+x);

}

}

}.start();//匿名内部类方式,创建线程

for(int i =0 ;i<199;i++)
{
System.out.println(Thread.currentThread().getName()+x);

}

Runnable r = new Runnable()

{
public void run()
{
for(int i =0 ;i<199;i++)
{
System.out.println(Thread.currentThread().getName()+x);

}

}
}

new Thread(r).start();
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: