• 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 ..

     

  • 相关阅读:
    [leedcode 82] Remove Duplicates from Sorted List II
    [leedcode 83] Remove Duplicates from Sorted List
    [leedcode 81] Search in Rotated Sorted Array II
    [leedcode 80] Remove Duplicates from Sorted Array II
    [leedcode 79] Word Search
    2018 ICPC青岛-books(思维题)
    CodeForces 15A-Cottage Village(思维题)
    CodeForces 755A-PolandBall and Hypothesis(思维题)
    CodeForces
    UVA11624-Fire!(BFS)
  • 原文地址:https://www.cnblogs.com/kikis/p/9783813.html
Copyright © 2020-2023  润新知