Java基础之详解Thread与Runnable

本文详细介绍了线程的概念及其实现方式,包括Thread类和Runnable接口的应用,并对比了这两种方式的区别。此外,还探讨了线程的生命周期及其状态控制方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 概念

线程是应用程序调度的最小单位;每个线程有独立的运行栈和程序计数器(PC);同一类线程共享内存,共享内存使线程之间的通信比进程之间通信更有效、容易;线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
我的另一篇博客:Java进阶之详解多线程

1.1 Thread类

通过使用Thread类,我们就可以启动,停止,中断一个线程. 在同一个时间片里, 可能会有多个线程在执行, 每个线程都拥有它自己的方法调用堆栈, 参数和变量.每个app至少会有一个线程–主线程(main thread).

1.2 Runnable接口

Runnable接口可声明一连串的事务,常用于多线程处理。但是实现Runnable接口并不意味着开启了一个新线程,只是定义了要做的事情,至于说这些事情要在UI线程处理,还是在非UI线程处理,那得看我们在哪里运行Runnable实例。如果在Handler或者View中启动Runnable,那么Runnable事务便运行于UI线程;如果在Thread中启动Runnable,那么Runnable事务便运行于非UI线程。

1.2.1 采用Handler类的post方法

(1)post : 立即启动Runnable
(2)postDelayed : 延迟指定时间间隔后启动Runnable
(3)postAtTime : 在指定时间启动Runnable
(4)removeCallbacks : 回收/移除指定的Runnable

private Handler mHandler;//全局变量
@Override
protected void onCreate(Bundle savedInstanceState) {
    .......
    mHandler = new Handler();
    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mTestTV.setText("This is post");//在主线程更新UI
                            }
                        });
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
}
1.2.2 使用View类的post方法

View类也提供了post和postDelayed两个方法,控件或视图可以直接调用自身的post方法,无需另外声明Handler对象。查看View的post源码,会发现其内部就是调用自身Handler实例的post方法。

1.2.3 利用Thread类构造Runnable的新线程

Thread方式启动Runnable,也只需两个步骤,第一步使用Runnable对象构造一个Thread实例,第二步启动这个Thread实例。

Thread runTread = new Thread(new Runnable() {  
	@Override  
    public void run() {  
    }  
});  
runTread.start(); 
1.2.4 参考链接

Android开发笔记(四十七)Runnable接口实现多线程

从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)

2 创建线程方式

2.1 第一种:直接建立一个Thread子线程,并启动。

   new Thread() {
		@Override
		public void run() {
		     //这里写入子线程需要做的工作
        }
   }.start();
   // 完毕
public class ThreadDemo1 {
     public static void main(String[] args){
         MyThread thread = new MyThread();
         thread.start();
         for(int i=0;i<60;i++){
           System.out.println(Thread.currentThread().getName()+i);
         }
     }
 }
 class MyThread extends Thread{
     public void run(){
         for(int i=0;i<60;i++){
             System.out.println(Thread.currentThread().getName()+i);
         }
     }
 }

2.2 第二种:建立一个Thread子线程,实现Runnable接口,然后启动。

//声明一个子线程
private Thread newThread = new Thread(new Runnable() {
    @Override
            public void run() {
	            //这里写入子线程需要做的工作
            }
        });
newThread.start(); //启动线程
public class ThreadDemo2 {
    public static void main(String[] args){
        MyRunnable runnable =new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
        for(int x=0;x<60;x++){
            System.out.println(Thread.currentThread().getName()+x);
        }
    }
}

class MyRunnable implements Runnable{
    public void run(){
        for(int x=0;x<60;x++){
            System.out.println(Thread.currentThread().getName()+x);
        }
    }
}

2.3 以上两种实现方式的区别和联系

(1)在程序开发中只要是多线程肯定永远以**“建立一个Thread子线程,实现Runnable接口,然后启动**”为主,因为实现Runnable接口相比继承Thread类有如下好处:

  • Runnable接口实质是共享代码,类似于函数调用,但又比函数调用灵活,因为Runnable可选择实际调用的时机,而不必像函数调用那样还得等待调用结束;
  • 可以避免Java单继承方式的局限。如果一个新类继承了Thread类,就不能再继承别的类。但是Runnable只是接口,所以新类可以继承别的类,同时实现Runnable接口。

(2)Runnable接口和Thread之间的联系:Thread类也是Runnable接口的子类 。

public class Thread extends Object implements Runnable 

2.4 常用方法

// 取得线程名称
getName();
// 取得当前线程对象
curentThread()
// 挂起和唤醒线程
public void resume( );    
// 得到线程状态,是否启动
publicboolean isAlive( );
// 线程睡眠,(Thread.sleep(1000))
public static void sleep(long millis);
public static void sleep(long millis, int nanos);
// 线程强行加入
publicvoid join( ) throws InterruptedException;

3 线程的生命周期

线程同样要经历“开始(等待)、运行、阻塞和停止”四种不同的状态。这四种状态都可以通过Thread类中的方法进行控制。
  这里写图片描述

// 开始
publicvoid start( );
// 运行
publicvoid run( );

// 阻塞

// 停止线程
publicvoid stop( );      

4 以卖票程序为例

(1)通过Thread类完成

class MyThread extends Thread{
      private int ticket=10;
      public void run(){
      for(int i=0;i<20;i++){
          if(this.ticket>0){
              System.out.println("卖票:ticket"+this.ticket--);
            }
      }
    }
 };
/**
 * 每个线程都各卖了10张,共卖了30张票,但实际只有10张票,
 * 每个线程都卖自己的票,没有达到资源共享
 */
public class ThreadTicket {
      public static void main(String[] args) {
          MyThread mt1 = new MyThread();
          MyThread mt2 = new MyThread();
          MyThread mt3 = new MyThread();
          mt1.start();
          mt2.start();
          mt3.start();
        }
  }

(2)通过Runnable方法完成

class MyTask implements Runnable{
      private int ticket=10;
      public void run(){
      for(int i=0;i<20;i++){
          if(this.ticket>0){
	          System.out.println("卖票:ticket"+this.ticket--);
          }
      }
  }
}

/**
 * 三个线程使用同一个Runnable--task,一共卖了10张票,
 * 说明使用Runnable实现多 线程达到资源共享目的。
 */
public class RunnableTicket {
      public static void main(String[] args) {
          MyTask task = new MyTask();
          new Thread(task).start();
          new Thread(task).start();//
          new Thread(task).start();
      }
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值