Java语言入门(九)——线程类及多线程
发布日期:2022-02-28 07:22:50 浏览次数:10 分类:技术文章

本文共 9675 字,大约阅读时间需要 32 分钟。

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
   {    //限制循环条件为存票序号小于总票数
 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
  {
//循环条件为售票序号小于总票数
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();   }}

转载地址:https://blog.csdn.net/weixin_45854582/article/details/106151329 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Java语言入门(十)——容器
下一篇:Java语言入门(十一)——流

发表评论

最新留言

不错!
[***.191.171.22]2022年10月06日 22时40分58秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章