Java实现多线程的方式

      多线程主要有两种实现方法,分别是继承Thread类实现Runnable接口。

      继承Thread类以后无法再继承其他类,但实现Runnable接口的方式解决了Java单继承的局限;此外,Runnable接口实现多线程可以实现数据共享(传递给Thread的参数均为实现Runnable接口的类的同一个对象)。

      启动一个线程是调用start()方法,它将启动一个新线程,使线程就绪状态,以后可以被调度为运行状态,同时在其中调用了native的方法(与操作系统有关);一个线程必须关联一些具体的执行代码,

run()方法是该线程所关联的执行代码。

一、继承Thread类

 重写Thread类的run方法即可,那么当线程启动的时候,就会执行run方法体的内容。代码如下:

public class ThreadDemo extends Thread {

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        td.start(); // 启动线程

        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 运行结果如下:

main is running ... 
Thread-0 is running ... 
main is running ... 
Thread-0 is running ... 
Thread-0 is running ... 
main is running ... 
Thread-0 is running ... 
main is running ...

      我们发现这里有个问题,多个线程的名字都是系统定义好的,就是Thread-开头,后面跟数字,如果我们每个线程处理不同的任务,那么我们能不能给线程起上不同的名字,方便我们排查问题呢?答案是可以的。只要在创建线程实例的时候,在构造方法中传入指定的线程名称即可。如:

    public ThreadDemo(String name) {
        super(name);
    }

二、实现Runnable接口

实现Runnable接口也是一种常见的创建线程的方式。使用接口的方式可以让我们的程序降低耦合度。

Runnable接口中仅仅定义了一个方法,就是run。我们来看一下Runnable接口的代码。

package java.lang;

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

       其实Runnable就是一个线程任务,线程任务和线程的控制分离,这也就是上面所说的解耦。

1、线程任务类

public class ThreadTarget implements Runnable {

    @Override
    public void run() {
        while(true) {
            System.out.println(Thread.currentThread().getName() + " is running .. ");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
} 

2、可运行的线程类

public class Main {

    public static void main(String[] args) {

        ThreadTarget tt = new ThreadTarget(); // 实例化线程任务类
        Thread t = new Thread(tt); // 创建线程对象,并将线程任务类作为构造方法参数传入
        t.start(); // 启动线程

        // 主线程的任务,为了演示多个线程一起执行
        while(true) {
            System.out.println(Thread.currentThread().getName() + " is running .. ");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

三、使用内部类的方式(另一种写法)

public class DemoThread {

    public static void main(String[] args) {

        // 基于子类的实现
        new Thread() {
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
                    try {
                        Thread.sleep(1000); // 休息1000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        }.start();

        // 基于接口的实现
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
                    try {
                        Thread.sleep(1000); // 休息1000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        // 主线程的方法
        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
} 

四、定时器

  • 例1:在2017年10月11日晚上10点执行任务。
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 定时器举例
 * 
 */
public class TimerDemo {

    private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 
    public static void main(String[] args) throws Exception {
Timer timer
= new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("定时任务执行了...."); } }, format.parse("2017-10-11 22:00:00")); }
}
  • 例2: 每隔5s执行一次
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo2 {
    public static void main(String[] args) {
Timer timer
= new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("Hello"); } }, new Date(), 5000); } }

五、带返回值的线程实现方式

1. 创建一个类实现Callable接口,实现call方法。这个接口类似于Runnable接口,但比Runnable接口更加强大,增加了异常和返回值。

public interface Callable<V>   { 
  V call() throws Exception;   
} 

2. 创建一个FutureTask,指定Callable对象,作为线程任务。

3. 创建线程,指定线程任务FutureTask。

4. 启动线程。

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

public class CallableTest {
    public static void main(String[] args) throws Exception {
Callable
<Integer> call = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("thread start .. "); Thread.sleep(2000); return 1;//可以返回一个Integer值 } }; FutureTask<Integer> task = new FutureTask<>(call);
Thread t
= new Thread(task); t.start();
System.out.println(
"do other thing .. "); System.out.println("拿到线程的执行结果 : " + task.get()); //可以通过FutureTask的get()方法获得返回值,注意:get方法是阻塞的,线程无返回结果,get方法会一直等待。
    }
}

运行结果如下:

do other thing .. 
thread start .. 
拿到线程的执行结果 : 1

六、基于线程池的方式

那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {

        // 创建线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        while(true) {
            threadPool.execute(new Runnable() { // 提交多个线程任务,并执行

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " is running ..");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

运行结果如下:

pool-1-thread-4 is running ..
pool-1-thread-1 is running ..
pool-1-thread-6 is running ..
pool-1-thread-2 is running ..
pool-1-thread-8 is running ..
pool-1-thread-3 is running ..
pool-1-thread-5 is running ..
pool-1-thread-9 is running ..
pool-1-thread-10 is running ..
pool-1-thread-7 is running ..

 

原文地址:https://www.cnblogs.com/kikis/p/9783813.html