Java语言入门(九)——线程类及多线程

线程与进程

1 进程是指运行中的应用程序,每一个进程都有自己独立的内存空间。对一个应用程序可以同时启动多个进程。
2 线程是指进程中的一个执行流程,有时也称为执行情景。一个进程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。当进程内的多个线程同时运行,这种运行方式称为并发运行。
3 进程消失了,线程还存在么?答:不在
4 线程消失了,进程还会存在么?答:可能在
5 线程依附进程 比进程小,不同进程的线程不可比较大小
JVM 对于一个java系统,至少要启动两个线程main gc

java.lang.Thread	
public static Thread currentThread()
public final String getName()

class Test
{  public static void main(String args[])
   { System.out.println(Thread.currentThread().getName()); }
}

线程的创建和启动方法

1 定义一个Thread类的子类,覆盖Thread类的run()方法,然后创建该子类的实例。
2 定义一个实现Runnable接口的类,实现它的run()方法,然后将这个类的实例作为Thread的构造方法的参数,创建Thread类的实例。
3 两种创建线程的方法是有区别的,对于共享资源来说,最好用实现runnable接口的方法

class TT extends Thread//线程的第一种创建方法
{  public void run()
    {  for(int i=0;i<10;i++)
        System.out.println(Thread.currentThread().getName());}
}
class Test-9.1
{  public static void main(String[] args)
    {   TT t1=new TT();
         t1.run();
  System.out.println(Thread.currentThread().getName()+";");}
}
//输出11个main
class TT extends Thread
{  public void run()
    {  for(int i=0;i<10;i++)
       System.out.println(Thread.currentThread().getName()); }
}
class Test-9.2
{  public static void main(String[] args)
   {  TT t1=new TT();
       //t1.run();
       t1.start();//线程的启动
  System.out.println(Thread.currentThread().getName()+";");}
}
//输出main;和10个Thread-0
class TT extends Thread
{  public void run()
    {  for(int i=0;i<10;i++)
       System.out.println(Thread.currentThread().getName()); }
}
class Test-9.3
{  public static void main(String[] args)
   {  TT t1=new TT();
       TT t2=new TT();
       TT t3=new TT();
       t1.setName("huang");
       t1.start();    t2.start();     t3.start();
System.out.println(Thread.currentThread().getName()+";");}
}
class TT implements Runnable//线程的第二种创建方法
{  public void run()
   {  for(int i=0;i<10;i++)
       System.out.println(Thread.currentThread().getName());}
}
class Test-9.4
{  public static void main(String[] args)
    {  Runnable t=new TT();
        Thread t1=new Thread(t);
        t1.start();
  System.out.println(Thread.currentThread().getName()+";");}
}
//输出main;和10个Thread-0
class TT extends Thread//实现售票
{  /*static*/ int tickets=20;
    public void run()
    {  //int tickets=20;错误
       for (int i=0;i<40;i++)
       {  if (tickets>0)
     {System.out.println(Thread.currentThread().getName()
+";"+tickets--);  }}}  }
class Test-9.5
{  public static void main(String args[])
    {  TT t1=new TT(); t1.setName("1");
       TT t2=new TT(); t2.setName("2");
       TT t3=new TT(); t3.setName("3");
       t1.start();  t2.start();  t3.start();
      System.out.println(Thread.currentThread().getName()
+"*****");} }
class TT implements Runnable//实现售票
{  /*static*/ int tickets=20;
    public void run()
    {  //int tickets=20;错误
       for (int i=0;i<40;i++)
       {  if (tickets>0)
     {System.out.println(Thread.currentThread().getName()
+";"+tickets--);  }}}  }
class Test-9.6
{  public static void main(String args[])
    {  TT t1=new TT(); /*TT t2=new TT();TT t3=new TT();*/
        new Thread(t1,"1").start();
        new Thread(t1,"2").start();
        new Thread(t1,"3").start();
      System.out.println(Thread.currentThread().getName()
+"*****");} }
class TT implements Runnable
{  static int tickets=20;
    public void run()/*throws Exception 错误*/
    {  for(int i=0;i<40;i++)
        {  if(tickets>0)
	{try { Thread.sleep(500);}
//只是让线程执行速度减缓,不影响代码执行本身
	 catch(Exception e){}
      System.out.println(Thread.currentThread().getName()
+":"+tickets--);}}
    }
}
class Test-9.7
{  public static void main(String[] args) throws Exception
   {   TT t1=new TT();
       TT t2=new TT();
       TT t3=new TT();
       new Thread(t1,"1站").start();
       new Thread(t2,"2站").start();
       new Thread(t3,"3站").start();
}
//出现错误有:重复、0、-1
//线程的安全性问题(同步)

线程同步synchronized(同步代码块、同步方法)以及锁旗标

class TT implements Runnable
{  static int tickets=20;
   String name="huang";
    public void run()
    {  for(int i=0;i<40;i++)
        {  synchronized(name) //同步代码块
            //synchronized(this)
	{ if(tickets>0)
	{try { Thread.sleep(500);}
//只是让线程执行速度减缓,不影响代码执行本身
	 catch(Exception e){}
      System.out.println(Thread.currentThread().getName()
+":"+tickets--);}}
    }
}
class Test-9.8
{  public static void main(String[] args) throws Exception
   {   TT t1=new TT();
       TT t2=new TT();
       TT t3=new TT();
       new Thread(t1,"1站").start();
       new Thread(t2,"2站").start();
       new Thread(t3,"3站").start();
}
 //synchronized(公认对象名[锁旗标])
/*添加同步代码块对象,必须是公认的。不能在run方法里,若在run方法则无效*/

售票实例讲解

public class ProducerAndConsumer 
{  /** 
     * 假定开始售票处并没有票,一个线程往里存票,另一个线程则往外卖票。 
     * 新建一个票类对象,让存票和售票线程都访问它。 
     * 两个线程共享同一个数据对象来实现对同一份数据的操作 
     */  
    public static void main(String[] args) 
   {  Tickets t=new Tickets(10); //新建一个票类对象,总票数作为参数  
       new Producer(t).start(); //以票类对象为参数创建存票线程对象,并启动  
       new Consumer(t).start();//以同一个票类对象为参数创建售票线程,并启动  
    }   
}  
//票类  
class Tickets
{  int number=0; //票号  
    int size;   //总票数  
    boolean available=false; //表示目前是否有票可售  
    public Tickets(int size){this.size=size;}//构造函数,传入总票数参数  
}
 //存票线程  
class Producer extends Thread
{  Tickets t=null;  
    public Producer(Tickets t)
    {  this.t=t;   }//构造函数:以一个票类为参数  
    public void run() 
   {  while(t.number<t.size)
       {//限制循环条件为存票序号小于总票数  
       synchronized(t){//申请对象t的锁旗标 
      System.out.println("Producer puts ticket "+(++t.number));  
      t.available=true;//可以买票  
     }//自动释放锁旗标  
}  }  } 
//售票线程  
class Consumer extends Thread
{  Tickets t=null;  
    int i=0; 
    public Consumer(Tickets t)
    {  this.t=t;  } //构造函数:以一个票类对象为参数 
    public void run()
    {  synchronized(t)
       {  while(i<t.size)
          { //循环条件为售票序号小于总票数  
          if(t.available==true && i<=t.number)
             {System.out.println("consumer buys ticket "+(++i));   } 
             //有票可售且小于目前票序号  
             if(i==t.number)
              {   t.available=false;  } //当票已售到当前序号,则不可售  
  }  }  }  } 

//一个对象的锁旗标只有一个,所以利用对一个对象锁旗标的争夺,可以实现不同线程的互斥效果。当一个线程获得锁旗标后,需要改锁旗标的其他线程只能处于等待状态。
//另外, 也可以将此关键字加在方法上:
//取票方法  
public synchronized void sell()
{  if(!available)
{ //如果没有存票,则售票线程等待  
        try{   wait();  }  
         catch(Exception e){ }  
         System.out.println("consumer buys ticket "+(number));  
          available=false;  
          notify();//售票唤醒存票线程开始存票 
          if(number==size)
           { number=size+1; }
          //在售完最后一张票后,设置一个结束标志  
          //number>size表示售票结束  
 }  } 

Thread类的方法

1 currentThread() 返回当前运行的Thread对象。
2 start() 启动一个线程。
3 run() 线程体,由start()方法调用,当run()方法返回时,当前的线程结束。
4 stop() 使调用它的线程立即停止执行。
5 sleep(int n)使线程睡眠n毫秒,n毫秒后,线程可以再次运行。
6 suspend() 使线程挂起,暂停运行。
7 resume() 恢复挂起的线程,使其处于可运行状态(Runnable)。
8 yield() 将CPU控制权主动移交到下一个可运行线程。
9 setPriority() 设置线程优先级。 getPriority() 返回线程优先级。
10 setName() 设置线程的名字。 getName() 返回该线程的名字。
11 isAlive( ) 如果线程已被启动并且未被终止,那么isAlive( )返回true。如果返回false,则该线程是新创建或是已被终止的。

死锁

1 死锁是程序运行时发生的一种状态
2 产生原因:多个线程共享同一资源时,要进行加锁操作(同步),但是,过多的同步会造成死锁
3 当一个线程等待由另一个线程持有的锁,而后者正在等待已被第一个线程持有的锁时,就会发生死锁。Java不监测也不试图避免这种情况。因而保证不发生死锁就成了程序员的责任

class ST implements Runnable      //死锁程序的模拟:
{   int ticket=10;
     String str=new String("hh");
/*添加同步代码块对象,必须是公认的。不能在run方法里,若在run方法则无效*/
     public void run()
    {  if(str.equals("huang"))
       {  for (int i=0;i<30 ;i++ )   { this.sale(); }
        else
        {  for (int i=0;i<30 ;i++ )
           {  synchronized(str) 
//str称为锁旗标或监视器,有0,1状态,进去后为0,出来后为1
               {  if (ticket>0)
                  {  try{Thread.sleep(100); } 
                      catch (Exception e){}
                      synchronized(this) {} 
         System.out.println(Thread.currentThread().getName()+" :"+ticket--);
/*ticket>0和ticket--不是原子性操作时,解决方法:(1)代码写进同步代码,synchronized()速度慢,因为synchronized()每次检查状态*/
}}} }}
public synchronized void sale() 
//改为public void sale()不同步,同步方法的锁旗标为this
 //买票的方法,加上synchronized,该方法就同步
{   if (ticket>0)
    {  try {  Thread.sleep(100);}
        catch (Exception e){}
        synchronized(str){} 
        System.out.println("i am here");
        System.out.println(Thread.currentThread().getName()+" :"+ticket--);
}}}
class Test-9.10
{   public static void main(String[] args) 
     {   ST s=new ST();
          Thread t=new Thread(s,"station1");
          Thread t1=new Thread(s,"station2");
           t.start();
           try{Thread.sleep(100);}
           catch(Exception e){}
           s .str="huang";
            t1.start();
       } 
}

对象数组

class Person             //对象数组
{  String name;
    int age;
    int ID;
    public void say()
    { System.out.println(name+";"+age); }
}
class Test-9.11
{  public static void main(String[] args)
   {   Person[] p=new Person[10];//生成10个对象
         //对象数组。每个单元存放的都是一个对象
        Person s=new Person();
        p[0]=s;   
        p[0].name="zhangsan";  p[0].ID=1;p[0].say();
}

在这里插入图片描述

内存图讲解

1 程序中用关键字new出来的东西都是存放在heap segment。
2 程序中的局部变量存放在stack segment,这些局部变量是在具体方法执行结束之后,系统自动释放内存资源(而heap segment中的资源需要java垃圾回收机制来处理)。形参一定在栈stack内存里
3 程序中的方法,是内存中的code segment中的,而且是多个对象 共享一个代码空间区域。
4 static静态变量,需要放在内存中的data segment

生产者与消费者实例讲解

//生产者与消费者问题
//涉及线程的通信

class SZP  //山楂片
{  private int ID;
    public SZP(int ID)  {this.ID=ID;}
    public String toString() {return "SZP"+ID;}
}
class RQ  //容器
{  int top=0;
   SZP [] sz = new SZP[10];
   public synchronized void push(SZP s)
   {  if(top==sz.length)
     {  try{  this.wait();   }
     //wait时,锁给别人,才自动释放;sleep睡觉时,锁还在。
        catch (Exception e){  }  }
      this.notify();   //notify()唤醒,唤醒的是别人,不是自己
      sz[top]=s;
      top++;
    }
    public synchronized SZP pop()
    {  if(top==0)
       {   try{this.wait();}   
            catch (Exception e){  }   }
        this.notify(); 
         top--;
         return sz[top]; 
    }
}
class Producer implements Runnable  //生产者
{  RQ r=null;
    public Producer(RQ r) { this.r=r;}
    public void run()
    {  for(int i=0;i<30;i++)
       {   SZP s=new SZP(i);
            r.push(s);
            try{Thread.sleep(10);}   
            catch (Exception e){  } 
            System.out.println("produce: "+s); } }
}
class Consumer implements Runnable //消费者
{  RQ r=null;
    public Consumer(RQ r) { this.r=r;}
    public void run()
      {  for(int i=0;i<30;i++)
         {  SZP s=r.pop();
             try{ Thread.sleep(1000);}   
             catch (Exception e){  }
             System.out.println("consumer: "+s); } }
}
class Test-9.12
{  public static void main(String [] args)
   {  RQ r=new RQ();
       Producer p=new Producer(r);
       Consumer c=new Consumer(r);
       new Thread(p).start();
       new Thread(c).start();   }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值