Java高并发——多线程基础

       在上一篇 JAVA高并发——了解并行世界 中我们回顾了一些多线程的概念知识。这里先举个例子,来看现实生活中的多线程例子:一个家庭中有爸爸、妈妈、儿子,家中有电视、洗衣机、书桌等,如果妈妈领着儿子出去了,爸爸就可以想干什么干什么(单线程);如果三人都在家,妈妈可以洗衣服、爸爸在书桌上工作、儿子看动画片(三个线程使用不同的资源互不影响);如果儿子看动画片,爸爸想看NBA视频,就得等着儿子看完了(多线程公用资源,出现阻塞)……看见了吧,其实我们就是把程序编写的如何像现实生活一样,多个任务同时进行,有共享资源,有各自资源,但是大家能够有条不紊的进行着……

      好,这篇我们来复习一下Java多线程的一些基础知识,来看下这张思维导图:

       一,首先需要了解线程的状态有哪些,怎么扭转,其实也就是生命周期(现实生活做事也是可以这样抽象)。我先看下Java,Thread类中对于state的定义:

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,

        /**
         * 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.
         */
        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>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

        好,看下这几种状态的相互转化吧:

       二,接下来看下线程的基本操作:

       1,新建线程:这个不用说了,通过继承Thread或者实现Runnable接口两种方式。

       2,终止线程:一般来说,线程执行完毕就会结束,无须自动关闭。但是对于一些while true的线程如果想关闭呢?Thread类里有stop()方法,但是已经不建议使用了。因为它是强制停止线程,无论线程处于什么状态,很容易出现线程正在处理一半数据被停止的情况,这样非常容易造成数据不一致问题。所以慎用stop()(最好不用),通过下边这种方式来停止哪些无限循环的线程:

public class StopThread extends Thread {

    volatile boolean stopme = false;

    //停止方法
    public void stopMe() {
        stopme = true;
    }

    @Override
    public void run() {
        while (true) {
            //死循环中如果出现停止标识,则直接跳出
            if (stopme) {
                System.out.println("exit by stop me");
                break;
            }

            System.out.println(System.currentTimeMillis());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

         3,线程中断:是一种线程协作机制。是告诉目标线程一个中断通知,至于接到通知后如何处理,则有线程自己决定处理。

public class InterruptThread {


    /**
     * public void interrupt() 中断线程
     * public static boolean interrupted() 判断是否被中断,并清除当前中断标识
     * public boolean isInterrupted() 判断是否被中断
     */
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    //判断如果有中断标识,则直接跳出
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("exit by interrupted");
                        break;
                    }

                    System.out.println(System.currentTimeMillis());
                    Thread.yield();
                }
            }
        };

        t1.start();
        Thread.sleep(2000);
        //打上中断标识
        t1.interrupt();
    }
}

      4,等待(wait)和通知(notify),也是为了支持线程之间的协作。方法都是在Object上定义的,例如线程A调用了obj.wiat()方法,那么线程A就会停止执行,等到其它线程调用obj.notify()方法为止。

public class WaitNotifyThread {
    final static Object ob = new Object();

    public static class T1 extends Thread {
        @Override
        public void run() {
            synchronized (ob) {
                System.out.println(System.currentTimeMillis() + "t1 is start");

                try {
                    System.out.println(System.currentTimeMillis() + "t1 is wait");
                    ob.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + "t1 is end");

            }
        }
    }


    public static class T2 extends Thread {
        @Override
        public void run() {
            synchronized (ob) {
                System.out.println(System.currentTimeMillis() + "t2 is start");


                System.out.println(System.currentTimeMillis() + "t2 is notify start");
                ob.notify();
                System.out.println(System.currentTimeMillis() + "t2 is notify end");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + "t2 is end");

            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new T1();
        Thread t2 = new T2();
        t1.start();
        t2.start();
    }
}

        5,挂起(suspend)和继续执行(resume):也是一对相对的操作,但是JDK也已经标示为废弃方法,不推荐使用。应为使用suspend()去挂起导致线程暂停的同时,并不释放资源,会阻塞其它线程,如果处理不当(例如resume()处理在suspend()之前了,就会导致一直阻塞),所以慎用。我们可以通过wait和notify来像实现stopMe()一样,实现自己一个挂起和继续执行操作。这里不再演示。

        6,等待线程结束(join)和谦让(yield):类似现实生活中,我做这件事得等着它做完那件事,我为他让让步等。很容易理解的:

public class JoinThread {
    volatile static int i = 0;

    public static  class AddThread extends Thread{
        @Override
        public void run() {
            for(i=0;i<10000;i++);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        AddThread addThread = new AddThread();
        addThread.start();
        //主线程等待addTread执行完毕
        addThread.join();
        System.out.println(i);
    }
}

       三,volatile:非常重要的关键字,如果用volatile修饰,虚拟机就会特殊处理,不能随意变动优化目标指令;并且修改后,各个线程都能看见它的改动,保证变量的可见性。在那个中共享变量是“一写多读”的情况下非常使用,保证修改及时可见。

       四,线程组:非常容易理解的概念,如果线程过多,为了方便管理,有了线程组,简单看下使用:

public class ThreadGroupTest implements Runnable {
    public void run() {
        String groupName = Thread.currentThread().getThreadGroup().getName() + "--" + Thread.currentThread().getName();
        while (true){
            System.out.println(" i am " + groupName);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ThreadGroup threadGroup = new ThreadGroup("testGroup");
        Thread t1 = new Thread(threadGroup,new ThreadGroupTest(),"T1");
        Thread t2 = new Thread(threadGroup,new ThreadGroupTest(),"T2");
        t1.start();
        t2.start();
        System.out.println(threadGroup.activeCount());
        threadGroup.list();
    }
}

          五,守护线程(Daemon):是一种特殊的线程,听名字猜想这种线程是系统的守护者。例如jvm的垃圾回收线程等。当一个Java应用中只有守护线程时,也就会自然退出:

public class DaemonDome {

    public static class T1 extends Thread {
        @Override
        public void run() {
            while (true) {
                System.out.println(" i am live");

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t = new T1();
        t.setDaemon(true);
        t.start();

        Thread.sleep(2000);
    }
}

       六,线程优先级,这个比较好理解,优先级从1到10数字越大优先级越高,只是说概率更高而已,而并非一定。Tread提供三个静态变量:

/**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

       七,线程安全和synchronized:线程安全就是针对共享资源能够高效有序的使用,不要出现同时修改,最终导致数据不一致的问题。而共享资源的同步使用即可解决。synchronized的作用就是实现线程间的同步。前边已经用到,我们不在看例子,总结一下它的用法:1,指定加锁对象:给对象加锁,进入同步代码前要获得给定对象的锁:synchronized(obj);2,直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁:synchronized(this);3,直接作用于静态方法:相当于当前类加锁,进入同步代码前要获得当前类的锁。

       好,高并发——Java多线程的复习总结就这样,还是说结合实际生活来学习联想。接下来,我们会继续……

猜你喜欢

转载自blog.csdn.net/liujiahan629629/article/details/84205788