创建线程的三种方式以及线程的状态(代码走一遍)

线程的特点:

1、抢占式线程

  • 效率高
  • 可防止单一线程长时间占用cpu

2、在单核cpu中,宏观上同时执行,微观上顺序执行。

线程的状态:

初始状态–就绪状态–运行状态–终止状态
此外还有限期等待(sleep(n))–无限期等待join()–阻塞状态(synchronized)

请看下图:
在这里插入图片描述
但是在JDK5之后,就绪状态和运行状态统称Runnable

具体的状态我们可以通过getState()方法看到。

public enum State {
    
    
        /**
         * Thread state for a thread which has not yet started.
         * 线程刚创建好之后的初始状态
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         * 线程的运行状态,或者等待时间片选中的状态为Runnable
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         * 未获得锁的状态
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         * 调用join方法后其他线程进入waitting状态
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         * 调用sleep方法后其他线程进入timed_waitting状态
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         * 线程终止状态
         */
        TERMINATED;
    }

创建线程的三种方式:

  • 1、继承Thread类,重写run方法
  • 2、实现Runnable接口
  • 3、实现Callable接口

1、继承Thread类,重写run方法

public class MyThread extends Thread{
    
    

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

    @Override
    public void run() {
    
    
        int i =100;
        for (int i1 = 0; i1 < i; i1++) {
    
    
            System.out.println("子线程"+i1+" 线程Name: "+ this.getName()+" :线程ID : "+this.getId());
        }
    }

    public static void main(String[] args) {
    
    
        MyThread myThread = new MyThread("nxw");

        myThread.start();

        MyThread myThread1 = new MyThread("silence");

        myThread1.start();

        for (int i=0;i<100;i++){
    
    
            System.out.println("主线程:"+i);
        }
    }
}

在MyThread 类中有一个main方法,在执行main方法的时候会开启一个主线程来执行,在执行过程中有开启了子线程来执行myThread.
从以上代码中执行结果会出现主线程的子线程交替打印的情况
但是如果你想先执行myThread,在执行myThread1,最后打印主线程的话,你只需要加上这样一段代码就可以了
myThread.join();
myThread1.join();

注意这时候就需要抛异常了throws InterruptedException

2、实现Runnable接口

public class MyRunnable implements Runnable {
    
    
    public synchronized void run() {
    
    

        for (int i = 0;i<101;i++){
    
    
            System.out.println("子线程ID:"+Thread.currentThread().getId()+"子线程Name:"+Thread.currentThread().getName()
            +"子线程:"+i);
        }

    }

}

class TestMyRunnable{
    
    


    public static void main(String[] args) {
    
    
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable,"runnable: ");
        Thread thread1 = new Thread(myRunnable,"runnable1: ");
        thread.start();
        thread1.start();

        for (int i = 0;i<101;i++){
    
    
            System.out.println("主线程:"+i);
        }
    }
}

3、实现Callable接口

public class TestCallable {
    
    
    public static void main(String[] args) {
    
    
        Callable<Integer> callable = new Callable<Integer>() {
    
    
            public Integer call() throws Exception {
    
    
                int sum = 0;
                for(int i=0;i<101;i++){
    
    
                    sum += i;
                }
                return sum;
            }
        };
        FutureTask task = new FutureTask(callable);

        Thread thread = new Thread(task);
        Thread thread1 = new Thread();
        thread.start();
        Object o = null;
        try {
    
    
            o = task.get();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } catch (ExecutionException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(o);
        //打印结果5050
    }
}

以上就是实现多线程的三种方式,但是要着重说一下实现Callable这种方式。
根据代码可以看出来,实现Callable后不能直接把对象给Thread对象,而是要经过FutureTask 包装后才能交给Thread。再仔细一点你就会发现实现Callable接口还需要抛出异常

通过以上代码我们可以总结一下三种创建线程方式的区别:

三种创建线程方式的区别

1、实现线程方式大体可分为两类,一类是继承,一类是接口实现。
2、接口实现可以避免单继承的局限性。
3、Runnable要实现的方法是run()方法,Callable()要实现的方法是call()方法。
4、Callable任务执行完毕后会有返回值,而Runnable是没有返回值的。
5、call()方法需要抛异常,而run()方法不需要抛异常。
6、Callable对象需要交给FutureTask对象包装后才能交给Thread开启线程,而Runnable可以直接交给Thread。
7、Callable执行完毕后可以通过futureTask获取线程执行结果。

猜你喜欢

转载自blog.csdn.net/nxw_tsp/article/details/109210614