问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

在JAVA中怎么实现消息队列

发布网友 发布时间:2022-04-21 00:55

我来回答

2个回答

热心网友 时间:2022-06-03 21:40

展开3全部java中的消息队列
消息队列是线程间通讯的手段:

import java.util.*

public class MsgQueue{

   private Vector queue = null;
   public MsgQueue(){
              queue = new   Vector();
   }
   public synchronized void send(Object o)
   {
      queue.addElement(o);
   }
   public synchronized Object recv()
{
     if(queue.size()==0)
        return null;
     Object o = queue.firstElement();
     queue.removeElementAt(0);//or queue[0] = null can also work
     return o;
}
}

因为java中是locked by object的所以添加synchronized 就可以用于线程同步锁定对象
可以作为多线程处理多任务的存放task的队列。他的client包括封装好的task类以及thread类

Java的多线程-线程间的通信2009-08-25 21:58
1. 线程的几种状态
线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
3) 死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。
4) 停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程重新回到可执行状态时,它有可能重新执行。如通过对一个线程调用wait()函数后,线程就进入停滞状态,只有当两次对该线程调用notify或notifyAll后它才能两次回到可执行状态。
2. class Thread下的常用函数函数
2.1 suspend()、resume()
1) 通过suspend()函数,可使线程进入停滞状态。通过suspend()使线程进入停滞状态后,除非收到resume()消息,否则该线程不会变回可执行状态。
2) 当调用suspend()函数后,线程不会释放它的“锁标志”。
例11:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
if(shareVar==5){
this.suspend(); //(1)
}}}
else{
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.resume(); //(2)
}}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(5)
//t1.start(); //(3)
t2.start(); //(4)
}}
运行结果为:
t2 shareVar = 5
i. 当代码(5)的t1所产生的线程运行到代码(1)处时,该线程进入停滞状态。然后排程器从线程池中唤起代码(4)的t2所产生的线程,此时shareVar值不为0,所以执行else中的语句。
ii. 也许你会问,那执行代码(2)后为什么不会使t1进入可执行状态呢?正如前面所说,t1和t2是两个不同对象的线程,而代码(1)和(2)都只对当前对象进行操作,所以t1所产生的线程执行代码(1)的结果是对象t1的当前线程进入停滞状态;而t2所产生的线程执行代码(2)的结果是把对象t2中的所有处于停滞状态的线程调回到可执行状态。
iii. 那现在把代码(4)注释掉,并去掉代码(3)的注释,是不是就能使t1重新回到可执行状态呢?运行结果是什么也不输出。为什么会这样呢?也许你会认为,当代码(5)所产生的线程执行到代码(1)时,它进入停滞状态;而代码(3)所产生的线程和代码(5)所产生的线程是属于同一个对象的,那么就当代码(3)所产生的线程执行到代码(2)时,就可使代码(5)所产生的线程执行回到可执行状态。但是要清楚,suspend()函数只是让当前线程进入停滞状态,但并不释放当前线程所获得的“锁标志”。所以当代码(5)所产生的线程进入停滞状态时,代码(3)所产生的线程仍不能启动,因为当前对象的“锁标志”仍被代码(5)所产生的线程占有。
#p#2.2 sleep()
1) sleep ()函数有一个参数,通过参数可使线程在指定的时间内进入停滞状态,当指定的时间过后,线程则自动进入可执行状态。
2) 当调用sleep ()函数后,线程不会释放它的“锁标志”。
例12:
class TestThreadMethod extends Thread{
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
for(int i=0; i<3; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
try{
Thread.sleep(100); //(4)
}
catch(InterruptedException e){
System.out.println("Interrupted");
}}}
}
public class TestThread{public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); (1)
t1.start(); (2)
//t2.start(); (3)
}}
运行结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 0
t1 : 1
t1 : 2
由结果可证明,虽然在run()中执行了sleep(),但是它不会释放对象的“锁标志”,所以除非代码(1)的线程执行完run()函数并释放对象的“锁标志”,否则代码(2)的线程永远不会执行。
如果把代码(2)注释掉,并去掉代码(3)的注释,结果将变为:
t1 : 0
t2 : 0
t1 : 1
t2 : 1
t1 : 2
t2 : 2
由于t1和t2是两个对象的线程,所以当线程t1通过sleep()进入停滞时,排程器会从线程池中调用其它的可执行线程,从而t2线程被启动。
例13:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
for(int i=0; i<5; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
try{
if(Thread.currentThread().getName().equals("t1"))
Thread.sleep(200);
else
Thread.sleep(100);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}}
}}
public class TestThread{public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start();
//t1.start();
t2.start();
}}
运行结果为:
t1 : 0
t2 : 0
t2 : 1
t1 : 1
t2 : 2
t2 : 3
t1 : 2
t2 : 4
t1 : 3
t1 : 4
由于线程t1调用了sleep(200),而线程t2调用了sleep(100),所以线程t2处于停滞状态的时间是线程t1的一半,从从结果反映出来的就是线程t2打印两倍次线程t1才打印一次。
#p#2.3 yield()
1) 通过yield ()函数,可使线程进入可执行状态,排程器从可执行状态的线程中重新进行排程。所以调用了yield()的函数也有可能马上被执行。
2) 当调用yield ()函数后,线程不会释放它的“锁标志”。
例14:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){super(name);
}
public synchronized void run(){for(int i=0; i<4; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
Thread.yield();
}}
}
public class TestThread{public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start();
t1.start(); //(1)
//t2.start(); (2)
}
}
运行结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t1 : 0
t1 : 1
t1 : 2
t1 : 3
从结果可知调用yield()时并不会释放对象的“锁标志”。
如果把代码(1)注释掉,并去掉代码(2)的注释,结果为:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
从结果可知,虽然t1线程调用了yield(),但它马上又被执行了。
2.4 sleep()和yield()的区别
1) sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
2) sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。
例15:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
//Thread.yield(); (1)
/* (2) */
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}}}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
运行结果为:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
由结果可见,通过sleep()可使优先级较低的线程有执行的机会。注释掉代码(2),并去掉代码(1)的注释,结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t2 : 0
t2 : 1
t2 : 2
t2 : 3
可见,调用yield(),不同优先级的线程永远不会得到执行机会。
2.5 join()
使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能。
例16:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.println(" " + i);
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
try{
t1.join();
}
catch(InterruptedException e){}
t1.start();
}
}
运行结果为:
0
1
2
3
0
1
2
3
#p#3. class Object下常用的线程函数
wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。
3.1 wait()、notify()和notifyAll()
1) wait()函数有两种形式:第一种形式接受一个毫秒值,用于在指定时间长度内暂停线程,使线程进入停滞状态。第二种形式为不带参数,代表waite()在notify()或notifyAll()之前会持续停滞。
2) 当对一个对象执行notify()时,会从线程等待池中移走该任意一个线程,并把它放到锁标志等待池中;当对一个对象执行notifyAll()时,会从线程等待池中移走所有该对象的所有线程,并把它们放到锁标志等待池中。
3) 当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
例17:
下面,我们将对例11中的例子进行修改
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<10; i++){
shareVar++;
if(shareVar==5){
try{
this.wait(); //(4)
}
catch(InterruptedException e){}
}
}
}
if(shareVar!=0){
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.notify(); //(5)
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(1)
//t1.start(); (2)
t2.start(); //(3)
}}
运行结果为:
t2 shareVar = 5
因为t1和t2是两个不同对象,所以线程t2调用代码(5)不能唤起线程t1。如果去掉代码(2)的注释,并注释掉代码(3),结果为:
t1 shareVar = 5
t1 shareVar = 10
这是因为,当代码(1)的线程执行到代码(4)时,它进入停滞状态,并释放对象的锁状态。接着,代码(2)的线程执行run(),由于此时shareVar值为5,所以执行打印语句并调用代码(5)使代码(1)的线程进入可执行状态,然后代码(2)的线程结束。当代码(1)的线程重新执行后,它接着执行for()循环一直到shareVar=10,然后打印shareVar。
#p#3.2 wait()、notify()和synchronized
waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
例18:
class TestThreadMethod extends Thread{
public int shareVar = 0;
public TestThreadMethod(String name){
super(name);
new Notifier(this);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
System.out.println("i = " + shareVar);
try{
System.out.println("wait......");
this.wait();
}
catch(InterruptedException e){}
}}
}
}
class Notifier extends Thread{
private TestThreadMethod ttm;
Notifier(TestThreadMethod t){
ttm = t;
start();
}
public void run(){
while(true){
try{
sleep(2000);
}
catch(InterruptedException e){}
/*1 要同步的不是当前对象的做法 */
synchronized(ttm){
System.out.println("notify......");
ttm.notify();
}}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
}
}
运行结果为:
i = 1
wait......
notify......
i = 2
wait......
notify......
i = 3
wait......
notify......
i = 4
wait......
notify......
i = 5
wait......
notify......
4. wait()、notify()、notifyAll()和suspend()、resume()、sleep()的讨论
4.1 这两组函数的区别
1) wait()使当前线程进入停滞状态时,还会释放当前线程所占有的“锁标志”,从而使线程对象中的synchronized资源可被对象中别的线程使用;而suspend()和sleep()使当前线程进入停滞状态时不会释放当前线程所占有的“锁标志”。
2) 前一组函数必须在synchronized函数或synchronized block中调用,否则在运行时会产生错误;而后一组函数可以non-synchronized函数和synchronized block中调用。
4.2 这两组函数的取舍
Java2已不建议使用后一组函数。因为在调用suspend()时不会释放当前线程所取得的“锁标志”,这样很容易造成“死锁”。

热心网友 时间:2022-06-03 21:41

java中的消息队列
消息队列是线程间通讯的手段:

import java.util.*

public class MsgQueue{

private Vector queue = null;
public MsgQueue(){
queue = new Vector();
}
public synchronized void send(Object o)
{
queue.addElement(o);
}
public synchronized Object recv()
{
if(queue.size()==0)
return null;
Object o = queue.firstElement();
queue.removeElementAt(0);//or queue[0] = null can also work
return o;
}
}

因为java中是locked by object的所以添加synchronized 就可以用于线程同步锁定对象
可以作为多线程处理多任务的存放task的队列。他的client包括封装好的task类以及thread类

Java的多线程-线程间的通信2009-08-25 21:58
1. 线程的几种状态
线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
3) 死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。
4) 停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程重新回到可执行状态时,它有可能重新执行。如通过对一个线程调用wait()函数后,线程就进入停滞状态,只有当两次对该线程调用notify或notifyAll后它才能两次回到可执行状态。
2. class Thread下的常用函数函数
2.1 suspend()、resume()
1) 通过suspend()函数,可使线程进入停滞状态。通过suspend()使线程进入停滞状态后,除非收到resume()消息,否则该线程不会变回可执行状态。
2) 当调用suspend()函数后,线程不会释放它的“锁标志”。
例11:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
if(shareVar==5){
this.suspend(); //(1)
}}}
else{
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.resume(); //(2)
}}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(5)
//t1.start(); //(3)
t2.start(); //(4)
}}
运行结果为:
t2 shareVar = 5
i. 当代码(5)的t1所产生的线程运行到代码(1)处时,该线程进入停滞状态。然后排程器从线程池中唤起代码(4)的t2所产生的线程,此时shareVar值不为0,所以执行else中的语句。
ii. 也许你会问,那执行代码(2)后为什么不会使t1进入可执行状态呢?正如前面所说,t1和t2是两个不同对象的线程,而代码(1)和(2)都只对当前对象进行操作,所以t1所产生的线程执行代码(1)的结果是对象t1的当前线程进入停滞状态;而t2所产生的线程执行代码(2)的结果是把对象t2中的所有处于停滞状态的线程调回到可执行状态。
iii. 那现在把代码(4)注释掉,并去掉代码(3)的注释,是不是就能使t1重新回到可执行状态呢?运行结果是什么也不输出。为什么会这样呢?也许你会认为,当代码(5)所产生的线程执行到代码(1)时,它进入停滞状态;而代码(3)所产生的线程和代码(5)所产生的线程是属于同一个对象的,那么就当代码(3)所产生的线程执行到代码(2)时,就可使代码(5)所产生的线程执行回到可执行状态。但是要清楚,suspend()函数只是让当前线程进入停滞状态,但并不释放当前线程所获得的“锁标志”。所以当代码(5)所产生的线程进入停滞状态时,代码(3)所产生的线程仍不能启动,因为当前对象的“锁标志”仍被代码(5)所产生的线程占有。
#p#2.2 sleep()
1) sleep ()函数有一个参数,通过参数可使线程在指定的时间内进入停滞状态,当指定的时间过后,线程则自动进入可执行状态。
2) 当调用sleep ()函数后,线程不会释放它的“锁标志”。
例12:
class TestThreadMethod extends Thread{
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
for(int i=0; i<3; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
try{
Thread.sleep(100); //(4)
}
catch(InterruptedException e){
System.out.println("Interrupted");
}}}
}
public class TestThread{public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); (1)
t1.start(); (2)
//t2.start(); (3)
}}
运行结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 0
t1 : 1
t1 : 2
由结果可证明,虽然在run()中执行了sleep(),但是它不会释放对象的“锁标志”,所以除非代码(1)的线程执行完run()函数并释放对象的“锁标志”,否则代码(2)的线程永远不会执行。
如果把代码(2)注释掉,并去掉代码(3)的注释,结果将变为:
t1 : 0
t2 : 0
t1 : 1
t2 : 1
t1 : 2
t2 : 2
由于t1和t2是两个对象的线程,所以当线程t1通过sleep()进入停滞时,排程器会从线程池中调用其它的可执行线程,从而t2线程被启动。
例13:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
for(int i=0; i<5; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
try{
if(Thread.currentThread().getName().equals("t1"))
Thread.sleep(200);
else
Thread.sleep(100);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}}
}}
public class TestThread{public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start();
//t1.start();
t2.start();
}}
运行结果为:
t1 : 0
t2 : 0
t2 : 1
t1 : 1
t2 : 2
t2 : 3
t1 : 2
t2 : 4
t1 : 3
t1 : 4
由于线程t1调用了sleep(200),而线程t2调用了sleep(100),所以线程t2处于停滞状态的时间是线程t1的一半,从从结果反映出来的就是线程t2打印两倍次线程t1才打印一次。
#p#2.3 yield()
1) 通过yield ()函数,可使线程进入可执行状态,排程器从可执行状态的线程中重新进行排程。所以调用了yield()的函数也有可能马上被执行。
2) 当调用yield ()函数后,线程不会释放它的“锁标志”。
例14:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){super(name);
}
public synchronized void run(){for(int i=0; i<4; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
Thread.yield();
}}
}
public class TestThread{public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start();
t1.start(); //(1)
//t2.start(); (2)
}
}
运行结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t1 : 0
t1 : 1
t1 : 2
t1 : 3
从结果可知调用yield()时并不会释放对象的“锁标志”。
如果把代码(1)注释掉,并去掉代码(2)的注释,结果为:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
从结果可知,虽然t1线程调用了yield(),但它马上又被执行了。
2.4 sleep()和yield()的区别
1) sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
2) sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。
例15:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
//Thread.yield(); (1)
/* (2) */
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}}}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
运行结果为:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
由结果可见,通过sleep()可使优先级较低的线程有执行的机会。注释掉代码(2),并去掉代码(1)的注释,结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t2 : 0
t2 : 1
t2 : 2
t2 : 3
可见,调用yield(),不同优先级的线程永远不会得到执行机会。
2.5 join()
使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能。
例16:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.println(" " + i);
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
try{
t1.join();
}
catch(InterruptedException e){}
t1.start();
}
}
运行结果为:
0
1
2
3
0
1
2
3
#p#3. class Object下常用的线程函数
wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。
3.1 wait()、notify()和notifyAll()
1) wait()函数有两种形式:第一种形式接受一个毫秒值,用于在指定时间长度内暂停线程,使线程进入停滞状态。第二种形式为不带参数,代表waite()在notify()或notifyAll()之前会持续停滞。
2) 当对一个对象执行notify()时,会从线程等待池中移走该任意一个线程,并把它放到锁标志等待池中;当对一个对象执行notifyAll()时,会从线程等待池中移走所有该对象的所有线程,并把它们放到锁标志等待池中。
3) 当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
例17:
下面,我们将对例11中的例子进行修改
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<10; i++){
shareVar++;
if(shareVar==5){
try{
this.wait(); //(4)
}
catch(InterruptedException e){}
}
}
}
if(shareVar!=0){
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.notify(); //(5)
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(1)
//t1.start(); (2)
t2.start(); //(3)
}}
运行结果为:
t2 shareVar = 5
因为t1和t2是两个不同对象,所以线程t2调用代码(5)不能唤起线程t1。如果去掉代码(2)的注释,并注释掉代码(3),结果为:
t1 shareVar = 5
t1 shareVar = 10
这是因为,当代码(1)的线程执行到代码(4)时,它进入停滞状态,并释放对象的锁状态。接着,代码(2)的线程执行run(),由于此时shareVar值为5,所以执行打印语句并调用代码(5)使代码(1)的线程进入可执行状态,然后代码(2)的线程结束。当代码(1)的线程重新执行后,它接着执行for()循环一直到shareVar=10,然后打印shareVar。
#p#3.2 wait()、notify()和synchronized
waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
例18:
class TestThreadMethod extends Thread{
public int shareVar = 0;
public TestThreadMethod(String name){
super(name);
new Notifier(this);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
System.out.println("i = " + shareVar);
try{
System.out.println("wait......");
this.wait();
}
catch(InterruptedException e){}
}}
}
}
class Notifier extends Thread{
private TestThreadMethod ttm;
Notifier(TestThreadMethod t){
ttm = t;
start();
}
public void run(){
while(true){
try{
sleep(2000);
}
catch(InterruptedException e){}
/*1 要同步的不是当前对象的做法 */
synchronized(ttm){
System.out.println("notify......");
ttm.notify();
}}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
}
}
运行结果为:
i = 1
wait......
notify......
i = 2
wait......
notify......
i = 3
wait......
notify......
i = 4
wait......
notify......
i = 5
wait......
notify......
4. wait()、notify()、notifyAll()和suspend()、resume()、sleep()的讨论
4.1 这两组函数的区别
1) wait()使当前线程进入停滞状态时,还会释放当前线程所占有的“锁标志”,从而使线程对象中的synchronized资源可被对象中别的线程使用;而suspend()和sleep()使当前线程进入停滞状态时不会释放当前线程所占有的“锁标志”。
2) 前一组函数必须在synchronized函数或synchronized block中调用,否则在运行时会产生错误;而后一组函数可以non-synchronized函数和synchronized block中调用。
4.2 这两组函数的取舍
Java2已不建议使用后一组函数。因为在调用suspend()时不会释放当前线程所取得的“锁标志”,这样很容易造成“死锁”。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
Linux系统安装FTP服务器 Linux系统的网络文件共享 建筑的七盏明灯的内容简介 面向对象设计七大原则 简单说 交互设计七大定律 交互设计的“根”——七大定律 交互设计原则和理论2——七大定律 七大设计原则 附近的加油站有哪些 附近的加油站有哪些地方 java 数组队列 链表队列哪个好 JAVA中队列和栈的区别 「每天一道面试题」Java中的阻塞队列有哪些 java哪些消息队列比较好 JAVA中,常用的队列实现是哪个? java常用的几种数据结构,堆栈,队列,数组,链 Java中的队列都有哪些,有什么区别 IE浏览器菜单栏里没有“文件”选项 java中的队列都有哪些,有什么区别? java中的队列都有哪些 公安警校学员的肩章是什么样的? 特警肩上的军衔怎么分级别? 警察的肩章都是怎么分级别的? 警察肩上三朵花是什么级别 看交警肩章如何分辨他的级别? 警察的肩章怎么分别(要图片和解释) 中国公安警察的各种级别头衔分别是什么? 警察上的肩章是怎么分辨他们的等级的.~ 人民警察的肩章胸章是什么样子的? 公安巡特警是什么肩章 java 队列 java 为什么要使用队列 java为什么要使用队列 java中的队列用什么实现 现在最常用的Java消息队列中间件是哪个 java中的队列用什么实现? java消息队列是怎么实现数据持久化的 ie窗口里的菜单栏在哪里 格力空调自清洁有什么好处?主要清哪? 格力空调有自动清洁模式吗? 格力空调自清洁启动后几秒又关机? 格力空调怎么自清洁 格力空调蒸发器自清洁的操作方法: 格力空调自清洁怎么用 格力空调自动清洁有哪些注意事项? 格力空调有换新风静音无风感自动清理的空挂式空调吗 格力空调冷静王有自动清洁吗 格力空调冷静王有自动清洁吗? 格力云锦空调自动清洁怎么有卡卡的声响,是正常的吗 中国邮政便民服务站都有哪些业务?