• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • YouClaw
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
风吹花落泪如雨
博客园    首页    新随笔    联系   管理    订阅  订阅

JAVA多线程(一)-----线程的生命周期,创建与控制,

一、线程的创建和启动

1、继承Thread类创建线程类

 

run()方法的方法体代表了线程需要完成的任务。start()方法来启动该线程。

public class FirstThread extends Thread{
    private int i;
    public void run() {
        for( ; i < 100 ; i++ ) {
            //this获得当前线程,getName()返回当前线程的名字
            System.out.println(getName() + " " + i);
        }
    }
    
    public static void main(String[] args) {
        for(int i = 0; i < 100; i++) {
            //调用Thread的currentThread()方法获得当前线程
            System.out.println(Thread.currentThread().getName());
            if(i == 20) {
                //启动第一个线程
                new FirstThread().start();
                //启动第二个线程
                new FirstThread().start();
            }
        }
    }
}

使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量。

 

2、实现Runnable接口创建线程类

public class SecondThread implements Runnable{
    private int i;
    //run方法同样是线程执行体
    public void run() {
        for( ; i < 100 ; i++) {
            //Runnable,想获取当前线程,只能用Thread.currentThread()方法
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
    
    public static void main(String[] args) {
        for(int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if(i == 20) {
                SecondThread st = new SecondThread();
                //通过new Thread(target,name)方法创建新线程
                new Thread(st,"新线程1").start();
                new Thread(st,"新线程2").start();
            }
        }
    }
}

 

使用继承Runnable接口的方式创建的多个线程可以共享线程类的实例变量。因为Runnable对象只是线程的target,多个线程共享一个target,所以多个线程可以共享同一个线程类的实例变量

 

3、使用Callable和Future创建线程

Callable接口是Runnable接口的增强版。以call()方法作为线程执行体,比run()方法更加强大。1.call()方法可以有返回值。2.call()方法可以声明抛出异常

Callable不是Runnable的子接口,所以不能直接作为Thread的target,并且还有一个返回值。

Java5提供了Future接口来代表Callable接口里call()方法的返回值,有一个实现类FutureTask,这个实现类实现了Future接口和Runnable接口----可以作为Thread类的target。

Future接口里定义了如下方法来控制它关联的Callable任务:

boolean cancel(boolean mayInterruptIfRunning):试图取消该Future里关联的Callable任务

V get():返回Callable任务里call()的返回值。调用该方法导致程序阻塞,子线程结束后才会获得返回值

V get(long timeout,TimeUnit unit):最多阻塞timeout和unit指定的时间,超出时间会抛出TimeoutException异常

boolean isCancelled():如果在Callable任务正常完成前被取消,返回true

boolean isDone():如果Callable已经完成,返回true

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class ThirdThread {
    public static void main(String[] args) {
        //创建Callable对象
        ThirdThread rt = new ThirdThread();
        //先使用Lambda表达式创建Callable<Integer>对象
        //使用FutureTask来包装Callable对象
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for( ; i < 100 ; i++) {
                System.out.println(Thread.currentThread().getName() + " 的循环变量i的值: " + i);
            }
            //call()方法可以有返回值
            return i;
        });
        for(int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " 的循环变量i的值: " + i);
            if(i == 20) {
                //实质还是以Callable的对象来创建并启动线程的
                new Thread(task,"有返回值的线程").start();
            }
        }
        try {
            //获取线程返回值
            System.out.println("子线程的返回值: " + task.get());
        }catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}

 

三种创建线程方法对比:

Runnable接口和Callable接口:只实现了接口,还可以继承其他类。共享一个target对象,适合多个相同线程处理同一份资源,将CPU、代码、数据分开

Thread类:不能再继承其他父类。可以直接使用this获得当前线程。

总结:一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程

 

二、线程的生命周期

1、新建和就绪状态

程序new了一个线程之后,线程就处于新建状态,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。

当线程对象调用了start()之后,线程处于就绪状态,Java虚拟机为其创建方法调用栈和程序计数器,表示线程可以运行了。

至于该线程何时开始运行,取决于JVM里线程调度器的调度。

2、运行和阻塞状态

处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。

所有现代的桌面和服务器操作系统都采用抢占式调度策略;但一些小型设备如手机则可能采用协作式调度策略,必须由该线程主动放弃所占用的资源。

 

被阻塞的线程会在合适的时候重新进入就绪状态,等待线程调度器的再次调度。

3、线程死亡

线程会以如下三种方式结束,结束后就处于死亡状态:

run()或call()方法执行完成,线程正常结束。

线程抛出一个未捕获的Exception或Error。

直接调用该线程的stop()方法来结束该线程----容易导致死锁,不推荐使用

isAlive()方法:处于就绪,阻塞,运行,返回true;处于新建,死亡,返回false

 

三、控制线程

1、join线程

当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join线程执行完为止

join():等待被join的线程执行完成。

join(long millis):等待被join的线程的时间最长为millis毫秒,超出时间则不再等待。

public class JoinThread extends Thread{
    //提供一个有参数的构造器,用于设置该现成的名字
    public JoinThread(String name) {
        super(name);
    }
    
    public void run() {
        for(int i = 0; i < 100; i++) {
            System.out.println(getName() + " " + i);
        }
    }
    
    public static void main(String[] args) throws Exception {
        new JoinThread("新线程").start();
        for(int i = 0; i < 100; i++) {
            if(i == 20) {
                JoinThread jt = new JoinThread("被join的线程");
                jt.start();
                //main线程调用了jt线程的jt()方法,main线程必须等待jt执行结束才会向下执行
                jt.join();
            }
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

2、后台线程

后台线程:在后台运行,为其他线程提供服务。JVM的垃圾回收线程就是经典的后台线程

特征:如果所有的前台线程都死亡,后台线程会自动死亡。

public class DaemonThread extends Thread{
    public void run() {
        for(int i = 0; i < 1000; i++) {
            System.out.println(getName() + " " + i);
        }
    }
    
    public static void main(String[] args) throws Exception {
        DaemonThread t = new DaemonThread();
        //将此线程设置成后台线程
        t.setDaemon(true);
        t.start();
        for(int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        //-----程序执行到此处,前台线程(main线程 )结束-----
        //后台线程也应该随之结束
    }
}

3、线程睡眠:sleep

static void sleep(long millis):让当前正在执行的线程暂停millis毫秒,并进入阻塞状态 。

还有一个与sleep()方法有点相似的yield()静态方法:可以让当前正在执行的线程暂停,但不会阻塞,只是将线程转入就绪状态。

4、改变线程优先级

线程默认与创建它的父线程优先级相同,

Thread类提供了setPriority(int newPriority),用来设置和返回指定线程的优先级,参数是一个整数,范围是1~10之间。或使用三个静态常量:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

Thread.currentThread().setPriority(6)

由于不同的操作系统优先级不相同,为了更好的移植性,推荐使用三个静态常量。

 

posted @ 2018-08-21 20:26  风吹花落泪如雨  阅读(92)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3