中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > J2SE
Java之多线程(1)
作者:未知 时间:2005-07-24 21:14 出处:JR 责编:chinaitpower
              摘要:Java之多线程(1)
JAVA程序在运行时最少会产生两个线程:“主线程”、垃圾回收线程。
程序清单:ThreadDemo1.java
public class ThreadDemo1
{
    public static void main(String args[])
    {
        new TestThread().run();
        //循环输出
        while(true)
        {
            System.out.println("main thread is running");
        }
    }
}
 class TestThread        
{
    public void run()
    {
        while(true)
        {
            System.out.println(Thread.currentThread().getName() + 
            " is running");
        }
    }


启动一个线程,不是直接调用Thread子类对象的run方法,而是调用Thread子类对象的start(从Thread类中继承的)方法


程序清单:ThreadDemo2.java
public class ThreadDemo2
{
    public static void main(String args[])
    {
        new TestThread().start();        //    实际上是调用了线程类的run()方法
        //循环输出
        while(true)
        {
            System.out.println("main thread is running");
        }
    }
}
 class TestThread        
{
    public void run()
    {
        while(true)
        {
            System.out.println(Thread.currentThread().getName() + 
            " is running");
        }
    }
}



实现线程,不是只能通过继承Thread类来实现,还可以通过实现Runnable这个接口来实现线程
java.lang 
Class Thread
java.lang.Object
   java.lang.Thread
All Implemented Interfaces: 
Runnable 

    可以发现,Thread类也是实现了Runnable接口

程序清单:ThreadDemo3.java
public class ThreadDemo3
{
    public static void main(String args[])
    {
        //new TestThread ().start();
        TestThread tt= new TestThread();    //创建TestThread类的一个实例
        Thread t= new Thread(tt);        //创建一个Thread类的实例
        t.start();                        //使线程进入Runnable状态
        while(true)
        {
            System.out.println("main thread is running");
        }
    }
}
class TestThread implements Runnable         //extends Thread
{
    public void run()        //线程的代码段,当执行start()时,线程从此出开始执行
    {
        while(true)
        {
            System.out.println(Thread.currentThread().getName() +
            " is running");
        }
    }
}

用Thread继承而来的线程,一个线程序对象只能启动一次,无论调用多少遍start()方法,结果都只有一个线程

实现Runnable接口相对于继承Thread类来说,有如下显著好处:
1、    适合多个相干同程序代码的线程去处理同一资源的情况
2、    可以避免由于Java单继承特性带来的局限
3、    有利于程序的健壮性,代码能够被多个线程共享


程序清单:ThreadDemo4.java
public class ThreadDemo4
{
    public static void main(String [] args)
    {
        ThreadTest t=new ThreadTest();
        //一个线程对象只能启动一次,无论调用多少遍start()方法,结构都只有一个线程
        t.start();
        t.start();
        t.start();
        t.start();
    }
}
class ThreadTest extends Thread  
{
    private int tickets=100;
    public void run()
    {
        while(true)
        {
            if(tickets>0)
            System.out.println(Thread.currentThread().getName() +
                " is saling ticket " + tickets--);
        }
    }
}


修改后的ThreadDemo4
程序清单:ThreadDemo4.java
public class ThreadDemo4
{
    public static void main(String [] args)
    {
        ThreadTest t=new ThreadTest();
        //启动了四个线程,分别执行各自的操作
        new ThreadTest().start();
        new ThreadTest().t.start();
        new ThreadTest().t.start();
        new ThreadTest().t.start();
    }
}
class ThreadTest extends Thread  
{
    private int tickets=100;
    public void run()
    {
        while(true)
        {
            // Thread.currentThread().getName(),得到当前运行的线程的名称
            if(tickets>0)
            System.out.println(Thread.currentThread().getName() +
                " is saling ticket " + tickets--);
        }
    }
}

线程命名:getName()和setName()
    在Thread API中,使用getName方法读取当前的名字。

GetNameThreadDemo.java

/*
 *目的:getName()方法的使用
 *说明:getName()方法用于获得线程的名字
 */
public class GetNameThreadDemo extends Thread
{
  public void run()
  {
    for(int i=0;i<10;i++)
      printMsg();
  }
  public void printMsg()
  {
    //获得运行此代码的线程的引用
    Thread t = Thread.currentThread();
    String name = t.getName();
    System.out.println("name = "+name);
  }
  public static void main(String[] args)
  {
    GetNameThreadDemo t1 = new GetNameThreadDemo();
    t1.start();

    for(int i=0;i<10;i++)
    {
      t1.printMsg();
    }
  }
}

使用setName()
    使用setName()方法可以显示指定Thread对象的名字
    线程的名字一般在启动线程前设置,但也允许为已经运行的线程设置名字。允许两个Thread对象有相同的名字,但为了清晰起见,应该尽量避免这种情况。

SetNameThreadDemo.java
/*
 *目的:setName()方法的使用
 *说明:setName()方法可以设置一个线程的名称
 */

public class SetNameThreadDemo extends Thread
{
  public void run()
  {
    for(int i=0;i<10;i++)
    {
      printMsg();
    }
  }
  public void printMsg()
  {
    //获得运行此代码的线程的引用
    Thread t = Thread.currentThread();
    String name = t.getName();
    System.out.println("name = "+name);
  }
  public static void main(String args[])
  {
    SetNameThreadDemo tt = new SetNameThreadDemo();
    //在这里设置线程的名称
    tt.setName("test thread");
    tt.start();
    for(int i=0;i<10;i++)
    {
      tt.printMsg();
    }
  }
}


激活线程:start()和isAlive()
start()方法通知线程规划器这个新线程已准备就绪,而且应当在规划器的最早方便时间调用它的run()方法。
isAlive()方法,用来测试线程是否已经启动而且仍然启动。
/*
 *目的:isAlive()方法的使用
 *说明:isAlive()方法用于判断线程是否存活
 */

public class StartThreadDemo extends Thread{
  public void run()
  {
    for(int i=0;i<10;i++)
    {
      printMsg();
    }
  }
  public void printMsg()
  {
    //获得运行此代码的线程的引用
    Thread t = Thread.currentThread();
    String name = t.getName();
    System.out.println("name = "+name);
  }
  public static void main(String[] args) {
    StartThreadDemo t = new StartThreadDemo();
    t.setName("test Thread");
    System.out.println("before start() , t.isAlive() = "+t.isAlive());
    t.start();
    System.out.println("just after start() , t.isAlive() = "+t.isAlive());
    for(int i=0;i<10;i++)
    {
      t.printMsg();
    }
    //下面这段代码会随情况不同而不同,有时候可能输出false,有时候可能输出true
    System.out.println("at the end of main() , t.isAlive() = "+t.isAlive());
  }
}


可以发现通过继承Thread类只能创建一个资源对象,
下面是采用实现Runnable接口实现线程

程序清单:ThreadDemo5.java
public class ThreadDemo5
{
    public static void main(String [] args)
    {
        ThreadTest t=new ThreadTest();
//虽然启动了四个线程,但是起到了同步的作用
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }
}
class ThreadTest implements Runnable  //这里实现了Runnable接口
{
    private int tickets=100;
    public void run()
    {
        while(true)
        {
            if(tickets>0)
            System.out.println(Thread.currentThread().getName() +
                " is saling ticket " + tickets--);
        }
    }
}

public class DaemonThread
{
    public static void main(String args[])
{
    ThreadTest t = new ThreadTest() ;
    Thread tt = new Thread(t) ;
    /*
对Java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束,如果某个线程对象在启动(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程。
*/
tt.setDaemon(true) ;    //设置后台运行
tt.start();
}
}

class ThreadTest implements Runnable
{
    public void run()
{
    while(true)
    {
        // Thread.currentThread().getName(),得到当前运行的线程的名称
        System.out.println(Thread.currentThread().getName()+”is running.”);
}
}
}


使用Thread.sleep()
    此方法用于将线程短暂休眠
TwoThreadSleep.java
public class TwoThreadSleep extends Thread {
        public void run() {
                loop();
        }

        public void loop() {
                // get a reference to the thread running this
                Thread t = Thread.currentThread();
                String name = t.getName();

                System.out.println("just entered loop() - " + name);

                for ( int i = 0; i < 10; i++ ) {
                        try {
                                Thread.sleep(2000);
                        } catch ( InterruptedException x ) {
                                // ignore
                        }

                        System.out.println("name=" + name);
                }

                System.out.println("about to leave loop() - " + name);
        }

        public static void main(String[] args) {
                TwoThreadSleep tt = new TwoThreadSleep();
                tt.setName("my worker thread");
                tt.start();

                // pause for a bit
                try {
                        Thread.sleep(700);
                } catch ( InterruptedException x ) {
                        // ignore
                }

                tt.loop();
        }
}


join用来强制运行某一线程,下面的这个程序在I=100时会强制运行该线程

程序清单:JoinThread.java
public class JoinThread
{
    public static void main(String[] args)
    {
        ThreadTest t=new ThreadTest();
        Thread pp=new Thread(t);
        pp.start();
        int i=0;
        while(true)
        {
            if(i==100)
            {            
                try
                {
                    pp.join();            //强制一线程运行完后,在运行后面的线程
                }
                catch(Exception e)        //会抛出InterruptedException
                {
                    System.out.println(e.getMessage());
                }
            }
            System.out.println("main Thread "+i++);
        }
    }
}
class ThreadTest implements Runnable
{
    public void run()
    {
        String str=new String();
        int i=0;
        while(true)
        {
            System.out.println(Thread.currentThread().getName()+" "+i++);
        }
    }
}

EX:
/*
编写一个类MyThread,它继承自Thread类,该类有两个变量:线程的名字整型变量delay,该类的构造函数有两个参数,
分别初始化str和delay,用String类的对象str表示,类的frun方法中,先让线程休眠delay毫秒后,再打印线程的名字。
编写应用程序,创建MyThread类的三个对象t1、t2和t3,分别指定线程名字为“线程A”、“线程B”和“线程C”,
休眠时间为1000ms、2000ms、3000ms,并启动这三个线程。
*/
public class Exercise14 {
  public static void main(String args[])
  {
    MyThread t1,t2,t3 ;
    t1 = new MyThread("线程A",1000);
    t2 = new MyThread("线程B",2000);
    t3 = new MyThread("线程C",3000);
    t1.start();
    t2.start();
    t3.start();
  }
}
class MyThread extends Thread
{
  private String str ;
  private int delay ;
  public MyThread(String s,int d)
  {
    super(s) ;
    delay = d ;
  }
  public void run()
  {
    try {
      Thread.sleep(delay);
    }
    catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    System.out.println(getName()+"运行!");
  }


}练习2:
/*
编写一个类A,并实现Runnable接口,该类有两个变量:str(String类型)和delay(int类型),该类的构造方法有两个参数,
分别初始化str和delay。类中的run方法如下实现,休眠delay毫秒后,打印str。编写应用程序,分别用类A的两个对象作为参数
创建两个线程对象t1、t2;类A的两个对象的str分别指定为“A类对象1”、“A类对象2”,休眠时间为1000ms、2000ms
*/
public class Exercise15 {
  public static void main(String args[])
  {
    Thread t1,t2 ;
    t1 = new Thread(new A("A类对象1",1000)) ;
    t2 = new Thread(new A("A类对象2",2000)) ;
    t1.start();
    t2.start();
    try {
      t1.join();
      t2.join();
    }
    catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    System.out.println("线程运行完毕!");
  }
}
class A implements Runnable
{
  private String str ;
  private int delay;
  public A(String s,int d)
  {
    str = s ;
    delay = d ;
  }
  public void run()
  {
    try {
      Thread.sleep(delay);
    }
    catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    System.out.println(str+"运行!");
  }
}

中断线程:
    当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它。
例题:SleepInteerupt.java
public class SleepInterrupt
    extends Object
    implements Runnable {
  public void run() {
    try {
      System.out.println(
          "in run() - 这个线程休眠20秒");
      Thread.sleep(20000);
      System.out.println("in run() - 继续运行");
    }
    catch (InterruptedException x) {
      System.out.println(
          "in run() - 中断线程");
      return;
    }

    System.out.println("in run() - 休眠之后继续完成");
    System.out.println("in run() - 正常退出");
  }

  public static void main(String[] args) {
    SleepInterrupt si = new SleepInterrupt();
    Thread t = new Thread(si);
    t.start();

    //在此休眠是为确保线程能运行一会
    try {
      Thread.sleep(2000);
    }
    catch (InterruptedException x) {}

    System.out.println(
        "in main() - 中断其他线程");
    t.interrupt();
    System.out.println("in main() - 退出");
  }
}




查看线程的中断状态:isInterrupted()方法
    可以在Thread对象上调用isInterrupted()方法来检查任何线程的中断状态。
InterruptCheck.java
public class InterruptCheck extends Object {
        public static void main(String[] args) {
                Thread t = Thread.currentThread();
                System.out.println("Point A: t.isInterrupted()=" + t.isInterrupted());
                t.interrupt();
                System.out.println("Point B: t.isInterrupted()=" + t.isInterrupted());
                System.out.println("Point C: t.isInterrupted()=" + t.isInterrupted());

                try {
                        Thread.sleep(2000);
                        System.out.println("was NOT interrupted");
                } catch ( InterruptedException x ) {
                        System.out.println("was interrupted");
                }
                //在这里因为sleep抛出了异常,所以它清除了中断标志

                System.out.println("Point D: t.isInterrupted()=" + t.isInterrupted());
        }
}

class ThreadTest implements Runnable
{
    private int tickets = 100 ;
    public void run()
    {
        while(true)
        {
            //假如一个线程未执行完,而另一线程又运行此代码,则会出现不同步问题
            //为说明问题,将线程延迟
            if(tickets>0)
            {
                try
                {
                    Thread.sleep(10) ;        //在这里,让线程休息10毫秒
                }
                catch(Exception e)
                {
                    System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+
”is saling ticket”+tickets--);    //在这里有可能会打印出负数
}
}
}
}

public class Test 
{
    public static void main(String aregs[])
    {
        ThreadTest t = new ThreadTest() ;
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }
}

为解决上面的问题,可以引用同步代码块的概念
class ThreadTest implements Runnable
{
    private int tickets = 100 ;
//因为此字符串变量声明在类之中,所以所有线程都会共享此对象
String str = new String(“”);
    public void run()
    {
        while(true)
        {
            synchronized(str)        //在这里加上一个同步锁
{
            //假如一个线程未执行完,而另一线程又运行此代码,则会出现不同步问题
            //为说明问题,将线程延迟
            if(tickets>0)
            {
                try
                {
                    Thread.sleep(10) ;        //在这里,让线程休息10毫秒
                }
                catch(Exception e)
                {
                    System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+
”is saling ticket”+tickets--);    //在这里有可能会打印出负数
}
}
}
}
}

public class Test 
{
    public static void main(String aregs[])
    {
        ThreadTest t = new ThreadTest() ;
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }
}


之所以把String str = new String(“”) ;放在run方法之外,是因为如果将它在run方法中声明,则每个线程都会得到各自的str对象,这样是不可能同步的。

class ThreadTest implements Runnable
{
    private int tickets = 100 ;
    public void run()
    {
        //将此变量声明在run方法之中,这样每个线程都拥有各自的str,无法同步
String str = new String(“”);
        while(true)
        {
            synchronized(str)        //在这里加上一个同步锁
{
            //假如一个线程未执行完,而另一线程又运行此代码,则会出现不同步问题
            //为说明问题,将线程延迟
            if(tickets>0)
            {
                try
                {
                    Thread.sleep(10) ;        //在这里,让线程休息10毫秒
                }
                catch(Exception e)
                {
                    System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+
”is saling ticket”+tickets--);    //在这里有可能会打印出负数
}
}
}
}
}


同步函数
    除了可以对代码块进行同步外,也可以对函数实现同步,只要在需要同步函数定义前加上synchronized关键字即可。
class ThreadTest implements Runnable
{
    private int tickets = 100 ;
    public void run()
    {
        while(true)
        {
            sale() ;
}
}
public synchronized void sale()
{
    if(tickets>0)
    {
        try
        {    
            Thread.sleep(10) ;
}
catch(Exception e)
{
    System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+
”is saling ticket”+tickets--);
}
}
}

public class Test
{
    public static void main(String aregs[])
    {
        ThreadTest t = new ThreadTest() ;
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }
}


程序清单:ThreadDemo6.java
public class ThreadDemo6
{
    public static void main(String [] args)
    {
        ThreadTest t=new ThreadTest();
        new Thread(t).start();        //这个线程调用同步代码块
        t.str=new String("method"); 
        new Thread(t).start();        //这个线程调用同步函数
    }
}
class ThreadTest implements Runnable
{
    private int tickets=100;
    //同步监视
    String str = new String ("");
    public void run()
    {
        if(str.equals("method"))
        {
            while(true)
            {
             sale();
            }
        }
        else
        {
            while(true)
            {
synchronized(str)        //synchronized(this)    ,监视当前对象
                {
                    if(tickets>0)
{
try
{
        Thread.sleep(10);
}
catch(Exception e)
{
        System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+
" is saling ticket " + tickets--);
}
}            
}
}
    }
    public synchronized void sale()
    {
        if(tickets>0)
{
try
{
    Thread.sleep(10);
}
catch(Exception e)
{
    System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+" is saling ticket " + tickets--);
}
    }
}
    产生并启动第一个线程,这个线程不见得马上就开始运行,CPU可能还在原来的main线程上运行,并将str变量设置成了”method”。


银行问题的同步:
class CAdd
{
    private static int sum = 0  ;
    public synchronized static void add(int a)
    {
        int temp = sum ;
        try
            {
                Thread.sleep(100) ;
            }
            catch(Exception e)
            {}
            temp = temp+a ;
        sum = temp ;
        System.out.println(sum);
    }
}
class  Test extends Thread
{
    public static void main(String[] args) 
    {
        Test t1 = new Test() ;
        Test t2 = new Test() ;
        t1.start() ;
        t2.start() ;
    }
    public void run()
    {
        for(int i=0;i<3;i++)
            CAdd.add(100) ;
    }
}


死锁问题:

程序清单:Deadlock.java
class A
{
    synchronized void foo(B b)
    {
            String name=Thread.currentThread().getName();
            System.out.println(name+ " entered A.foo ");
            try
            {
                Thread.sleep(1000);
            }    
            catch(Exception e)
            {
                System.out.println(e.getMessage());
            }
            System.out.println(name+ " trying to call B.last()");
            b.last();
    }
    synchronized void last()
    {
            System.out.println("inside A.last");
    }
}
class B
{
    synchronized void bar(A a)
    {
            String name=Thread.currentThread().getName();
            System.out.println(name + " entered B.bar");
            try
            {
                Thread.sleep(1000);
            }
            catch(Exception e)
            {
                System.out.println(e.getMessage());
            }
            System.out.println(name + " trying to call A.last()");
            a.last();
    }
    synchronized void last()
    {
            System.out.println("inside A.last");
    }
}
class Deadlock implements Runnable
{
    A a=new A();
    B b=new B();
    Deadlock()
    {
            //设置当前线程名称
            Thread.currentThread().setName("MainThread");
            new Thread(this).start();
            a.foo(b);       //get lock on a in this thread.
            System.out.println("back in main thread");
    }
    public void run()
    {
            Thread.currentThread().setName("RacingThread");
            b.bar(a);  //get lock on a in other thread.
            System.out.println("back in other thread");
    }
    public static void main(String[] args)
    {
            new Deadlock();
    }
}

    从结果可以看出,RacingThread进入了b的监视器,然后又在等待a的监视器。同时MainThread进入了a的监视器并等待b的监视器。这个程序永远不会完成。


线程间通信
    一个线程向数据存储空间添加数据(生产者),另一个线程从数据存储空间取出数据(消费者)
    这个程序有两种以外需要考虑:
    1、    假设生产者线程刚向数据存储空间添加了一个人的姓名,还没有加入这个人的性别,CPU就切换到了消费者线程,消费者线程将把这个人的姓名和上一个恶人的性别联系到了一起
    2、    生产者放了若干次的数据,消费者才开始取数据,或者是,消费者取完一个数据后,还没等到生产者放入新的数据,又重复取出已取过的数据。

问题的解决:
class Producer implements Runnable
{
    public void run()
    {
        while(true)
        {
            编写往数据存储空间放入数据的代码
}
}
}
class Consumer implements Runnable
{
    public void run()
    {
        while(true)
        {
            编写从数据存储空间读取数据的代码
}
}
}

定义一个新的类来作为数据存储空间
class Q
{
    String name ;
    String sex ;
}
Producer和Consumer中的run函数都需要操作类Q的同一个对象实例



程序清单:ThreadCommunation.java
class Producer implements Runnable
{
    Q q=null;
    public Producer(Q q)
    {
        this.q=q;
    }
    public void run()
    {
        int i=0;
        while(true)
        {
            if(i==0)
            {
                q.name="张孝祥";
                q.sex="男";
            }
            else
            {
                q.name="陈琼";
                q.sex="女";
            }
            i=(i+1)%2;
        }
    }
}
class Q
{
    String name="陈琼";
    String sex="女";
}
class Consumer implements Runnable
{
    Q q=null;
    public Consumer(Q q)
    {
        this.q=q;
    }
    public void run()
    {
        while(true)
        {
            System.out.println(q.name + "---->" + q.sex);
        }
    }

public class ThreadCommunation
{
    public static void main(String [] args)
    {
        Q q=new Q();        //将引用传递过去
        new Thread(new Producer(q)).start();
        new Thread(new Consumer(q)).start();
    }
}

在这里Producer和Consumer访问的是同一个Q对象
可以发现在这里一切都是正常的结果,但假如在这里将某一线程延时的话,如下所示:
class Producer implements Runnable
{
    Q q=null;
    public Producer(Q q)
    {
        this.q=q;
    }
    public void run()
    {
        int i=0;
        while(true)
        {
            if(i==0)
            {
                q.name="张孝祥";
                //加入此段代码
                try
                {
                    Thread.sleep(10) ;
}
catch(Exception e)
{
    System.out.println(e.getMessage());
}
                q.sex="男";
            }
            else
            {
                q.name="陈琼";
                q.sex="女";
            }
            i=(i+1)%2;
        }
    }
}
class Q
{
    String name="陈琼";
    String sex="女";
}
class Consumer implements Runnable
{
    Q q=null;
    public Consumer(Q q)
    {
        this.q=q;
    }
    public void run()
    {
        while(true)
        {
            System.out.println(q.name + "---->" + q.sex);
        }
    }

public class ThreadCommunation
{
    public static void main(String [] args)
    {
        Q q=new Q();
        new Thread(new Producer(q)).start();
        new Thread(new Consumer(q)).start();
    }
}

这时再运行程序,可以发现结果出现了错误,这个时候可以才用前面提到的同步方法,对类Q中的代码进行同步,为了说明问题,在类Q中加入两个新方法,一个是设置,一个是取值
class Producer implements Runnable
{
    Q q=null;
    public Producer(Q q)
    {
        this.q=q;
    }
    public void run()
    {
        int i=0;
        while(true)
        {
            if(i==0)
            {
                q.put("张孝祥","男") ;
            }
            else
            {
                q.put("陈琼","女") ;
            }
            i=(i+1)%2;
        }
    }
}
class Q
{
    private String name="陈琼";
    private String sex="女";
    public synchronized void put(String name,String sex)
    {
        this.name = name ;
        try
        {
            Thread.sleep(10);
}
catch(Exception e)
{
    System.out.println(e.getMessage());
}
this.sex = sex ;
}
public synchronized void get()
{
    System.out.println(name+”--”+sex);
}
}
class Consumer implements Runnable
{
    Q q=null;
    public Consumer(Q q)
    {
        this.q=q;
    }
    public void run()
    {
        while(true)
        {
            System.out.println(q.name + "---->" + q.sex);
        }
    }

public class ThreadCommunation
{
    public static void main(String [] args)
    {
        Q q=new Q();
        new Thread(new Producer(q)).start();
        new Thread(new Consumer(q)).start();
    }
}


wati:告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify为止。
notify:唤醒同一对象监视器中调用wait的第一个线程。
notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。

class Q
{
    private String name="陈琼";
    private String sex="女";
    boolean bFull = false ;
    public synchronized void put(String name,String sex)
    {
        if(bFull)
            wati() ;                //后来的线程要等待
        this.name = name ;
        try
        {
            Thread.sleep(10);
}
catch(Exception e)
{
    System.out.println(e.getMessage());
}
this.sex = sex ;
bFull = true ;
notify();                    //唤醒最先到达的线程
}
public synchronized void get()
{
    if(!bFull)
        wait() ;
    System.out.println(name+”--”+sex);
    bFull = false ;
    notify();
}
}



控制线程的生命周期
控制线程生命周期的方法有很多种:如:suspend方法、resume方法和stop方法,不推荐使用suspend和resume方法是因为:
1、    会导致死锁的发生
2、    它允许一个线程(甲)通过直接控制另外一个线程(乙)的代码来直接控制那个线程(乙)。
虽然stop能够避免死锁的发生,但带来了另外的不足,如果一个线程正在操作共享数据段,操作过程没有完成就stop的话,将会导致数据的不完整性,所以stop方法也不提倡使用了。


public class ThreadLife
{
    public static void main(String args[])
    {
        ThreadTest t = new ThreadTest() ;
        new Thread(t).start() ;
        for(int I=0;I<100;I++)
        {
            if(I==50)
                t.stopMe() ;
            System.out.println(“mainThread is running”);
}
}
}

class ThreadTest implements Runnable
{
    private boolean bFlag = true ;
    public void stopMe()
    {
        bFlag = false ;
}
public void run()
{
    while(bFlag)
    {
        System.out.println(Thread.currentThread().getName()+
“is running”);
}
}
}

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有