Loading

Java的多线程

 

    Java使用Thread代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用就是执行一段程序流(完成一定的任务)。

Java使用线程执行体来代表这段程序流。

 1. 继承Thread类创建线程类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.apache;
 
public class ThreadDemo1 extends Thread {
    private int i;
    /*
     * 重写run方法,也就是线程执行体
     * 当线程类继承Thread类时,直接使用this即可取得当前线程
     * 直接调用getName()方法即可返回当前线程的名字
     */
    public void run(){
        for ( ; i<100;i++){
            System.out.println(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){
                //创建并启动第一个线程
                new ThreadDemo1().start();
                //创建并启动第二个线程
                new ThreadDemo1().start();
            }
        }
    }
}

  执行结果:

注意:实际上该程序有三个线程,main()方法是主线程,显示的创建了两个子线程。

   Thread-0和Thread-1 i的值是不连续的,所以Thread-0和Thread-1不能共享Thread类的实例变量。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.apache;
 
public class ThreadDemo2 implements Runnable {
    private int i;
    //当实现Runnable接口时必须用Thread.currentThread().getName()获取当前线程
    public void run() {
        for ( ; i<100;i++){
            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){
                ThreadDemo2 td = new ThreadDemo2();
                //通过new Thread(target,name)方法创建线程
                new Thread(td,"线程1").start();
                new Thread(td,"线程2").start();
            }
        }
 
    }
}

  结果:

i的值是连续的,共享同一个线程类的实例变量(其实是线程的target类)

3.使用Callable和Future创建线程

FutureTask同时实现

Future接口--->接收call()方法的返回值

和Runnable接口--->可以作为Thread的target

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
 
/*
 * 创建并启动有返回值的线程步骤:
 * 1. 创建Callable接口的实现类,并实现call()方法,作为线程执行体
 * 2. 使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的call()方法
 * 3. 使用FutureTask对象作为Thread对象的target创建并启动新线程
 * 4. 调用FutureTask对象的get()方法获得子线程的执行结束的返回值
 */
public class ThreadDemo3 implements Callable{
    private int i;
     
    public Object call() throws Exception {
        for ( ; i<100;i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        return i;
    }
 
    public static void main(String[] args) {
        ThreadDemo3 td = new ThreadDemo3();
        //通过new Thread(target,name)方法创建线程
        FutureTask<Integer> task = new  FutureTask<Integer>(td);
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + " "+i);
            if (i==20){
                new Thread(task,"有返回值的线程").start();
            }
        }
        try {<br>              //获取线程返回值
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }  
}

  结果:

 

4. 控制线程

4.1 join线程

当程序程序执行流中调用其它线程的join()方法时,调用线程将会被阻塞。直到被join的线程执行完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package org.apache;
 
public class ThreadDemo1 extends Thread {
    public ThreadDemo1 (String name){
        super(name);
    }
    private int i;
    /*
     * 重写run方法,也就是线程执行体
     * 当线程类继承Thread类时,直接使用this即可取得当前线程
     * 直接调用getName()方法即可返回当前线程的名字
     */
    public void run(){
        for ( ; i<100;i++){
            System.out.println(getName() + " " + i);
        }
    }
     
    public static void main(String[] args) throws InterruptedException
    {
        new ThreadDemo1("新线程").start();
        for (int i=0;i<100;i++){
            Thread task = new ThreadDemo1("被join的线程");
            System.out.println(Thread.currentThread().getName()
                    + " "+i);
            if(i==20){
                //创建并启动第一个线程
                task.start();
                //main调用了join()方法,必须等task执行结束后才会向下执行
                task.join();
            }
        }
    }
}

  

  执行结果:

 分析可知main方法(主线程)被阻塞,只有新线程和join线程并发执行。

 

4.2 守护线程

有一种线程是为其它线程提供服务的(典型的有GC),被称为后台线程或者守护线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package org.apache;
 
public class ThreadDemo4 extends Thread{
    private int i;
    public void run(){
        for (;i<1000;i++){
            System.out.println(getName() + " "+i);
        }
    }
 
    public static void main(String[] args) {
        ThreadDemo4 task = new ThreadDemo4();
        //设置为守护进程
        task.setDaemon(true);
        task.start();
        for( int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
        //程序执行到此处就main进程就结束了,JVM将会主动退出,守护线程也将被结束,无法执行到=999
    }
}

 执行结果: 

 

4.3 线程睡眠:sleep
1
2
3
4
5
6
7
8
9
10
11
12
13
package org.apache;
 
import java.util.Date;
 
public class ThreadDemo5 {
      //正在执行的线程将会暂停一段时间,进入阻塞状态
    public static void main(String[] args) throws InterruptedException {
        for (int i=0;i<10;i++){
            System.out.println("当前时间: "+new Date());
            Thread.sleep(1000);
        }
    }
}

  结果:

 

posted @   头痛不头痛  阅读(291)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示