精华内容
下载资源
问答
  • Java Thread类源码详解

    千次阅读 2018-08-23 14:51:18
    Java所有多线程的实现,均通过封装Thread类实现,所以深入Thread类,对深入理解java多线程很有必要 构造函数: Thread的构造函数,采用缺省的方式实现: //传入Runnable接口实现 Thread...

    概述

    Java所有多线程的实现,均通过封装Thread类实现,所以深入Thread类,对深入理解java多线程很有必要


    构造函数:
    • Thread的构造函数,采用缺省的方式实现:
    //传入Runnable接口实现
    Thread(Runnable target)
    //传入Runnable接口实现,传入线程名
    Thread(Runnable target, String name) 
    //设置当前线程用户组
    Thread(ThreadGroup group, Runnable target)
    //设置用户组,传入线程名
    Thread(ThreadGroup group, Runnable target, String name)
    //设置用户组,传入线程名,设置当前线程栈大小
    Thread(ThreadGroup group, Runnable target, String name, long stackSize) 
    
    • Thread类构造函数源码分析:
      1.线程默认名称生产规则:
    // 当前缺省线程名:"Thread-" + nextThreadNum()
    public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
    ---
    // nextThreadNum 同步方法,线程安全,不会出现重复的threadInitNumber
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }
    

    2.线程私有化实现

    /**
         * Initializes a Thread.
         *
         * @param g the Thread group
         * @param target the object whose run() method gets called
         * @param name the name of the new Thread
         * @param stackSize the desired stack size for the new thread, or
         *        zero to indicate that this parameter is to be ignored.
         * @param acc the AccessControlContext to inherit, or
         *            AccessController.getContext() if null
         * @param inheritThreadLocals if {@code true}, inherit initial values for
         *            inheritable thread-locals from the constructing thread
         */
        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize, AccessControlContext acc,
                          boolean inheritThreadLocals) {
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
    
            this.name = name;
    
            Thread parent = currentThread();
            SecurityManager security = System.getSecurityManager();
            if (g == null) {
                /* Determine if it's an applet or not */
    
                /* If there is a security manager, ask the security manager
                   what to do. */
                if (security != null) {
                    g = security.getThreadGroup();
                }
    
                /* If the security doesn't have a strong opinion of the matter
                   use the parent thread group. */
                if (g == null) {
                    g = parent.getThreadGroup();
                }
            }
    
            /* checkAccess regardless of whether or not threadgroup is
               explicitly passed in. */
            g.checkAccess();
    
            /*
             * Do we have the required permissions?
             */
            if (security != null) {
                if (isCCLOverridden(getClass())) {
                    security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
                }
            }
    
            g.addUnstarted();
    
            this.group = g;
            /* 设置当前线程是否为守护线程,默认是和当前类的ThreadGroup设置相
            * 同。如果是守护线程的话,当前线程结束会随着主线程的退出而退出。
            *jvm退出的标识是,当前系统没有活跃的非守护线程。
            */
            this.daemon = parent.isDaemon();
            /*设置的线程的访问权限默认为当前ThreadGroup权限*/
            this.priority = parent.getPriority();
            if (security == null || isCCLOverridden(parent.getClass()))
                this.contextClassLoader = parent.getContextClassLoader();
            else
                this.contextClassLoader = parent.contextClassLoader;
            this.inheritedAccessControlContext =
                    acc != null ? acc : AccessController.getContext();
            this.target = target;
            setPriority(priority);
            if (inheritThreadLocals && parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
            /* Stash the specified stack size in case the VM cares */
            /*设置指定的栈大小,如果未指定大小,将在jvm 初始化参数中声明:Xss参数进行指定*/
            this.stackSize = stackSize;
    
            /* Set thread ID */
            tid = nextThreadID();
        }
    

    start()方法源码分析:
    /*  导致此线程开始执行; Java Virtual Machine调用此线程的run方法。
        结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。
        不止一次启动线程永远不合法。
        特别是,一旦完成执行,线程可能无法重新启动。
        @exception IllegalThreadStateException如果线程已经启动。
        @see #run()
        @see #stop()*/
    
     public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            //此判断当前线程只能被启动一次,不能被重复启动
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
    
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            /*通知组该线程即将启动
              *这样它就可以添加到组的线程列表中
             *并且该组的未启动计数可以递减。*/
            group.add(this);
    
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    // 如果线程启动失败,从线程组里面移除该线程
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }
    

    join() 方法源码分析:
    /**
         * Waits at most {@code millis} milliseconds for this thread to
         * die. A timeout of {@code 0} means to wait forever.
         *
         * <p> This implementation uses a loop of {@code this.wait} calls
         * conditioned on {@code this.isAlive}. As a thread terminates the
         * {@code this.notifyAll} method is invoked. It is recommended that
         * applications not use {@code wait}, {@code notify}, or
         * {@code notifyAll} on {@code Thread} instances.
         *
         * @param  millis
         *         the time to wait in milliseconds
         *
         * @throws  IllegalArgumentException
         *          if the value of {@code millis} is negative
         *
         * @throws  InterruptedException
         *          if any thread has interrupted the current thread. The
         *          <i>interrupted status</i> of the current thread is
         *          cleared when this exception is thrown.
         */
        public final synchronized void join(long millis) throws InterruptedException {
            long base = System.currentTimeMillis();
            long now = 0;
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (millis == 0) {
            // 如果millis == 0 线程将一直等待下去
                while (isAlive()) {
                    wait(0);
                }
            } else {
                // 指定了millis ,等待指定时间以后,会break当前线程
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }
    

    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中的一个线程
             * state正在Java虚拟机中执行但它可能正在执行
             * 等待操作系统中的其他资源
             * 如处理器。
             */
            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;
        }
    

    线程六种状态之间的关系,其中进入阻塞状态是java虚拟机自定义状态,通常都是遇到获取当前锁,synchronize代码同步块

    image


    run()方法源码:
    /*Thread类重写了Runnable接口的run()方法。
     该run()方法首先判断当前是否有Runnable的实现target存在。
     如果存在就执行target.run()
    */
     @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
    

    run 方法的实现,是通过Java静态代理的方式实现的。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lm7AJmJe-1577089548842)(http://i.imgur.com/oh3VMNs.gif)]


    展开全文
  • Java Thread类主要方法详解

    万次阅读 2018-09-13 00:48:41
    java中,谈到线程,必然少不了Thread类。线程是比进程更轻量级的调度执行单位。为什么用线程?通过使用线程,可以把操作系统进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),...

    在java中,谈到线程,必然少不了Thread类。线程是比进程更轻量级的调度执行单位。为什么用线程?通过使用线程,可以把操作系统进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度(线程是CPU调度的基本单位)。

    主流操作系统(Windows, Linux)都提供了线程的实现,Java则提供了在不同硬件和操作系统下对线程的统一处理,Thread类则是Java中线程的实现。

    Java线程的实现方式:

    Java线程使用操作系统的内核线程实现,内核线程(Kernel-Level Thread, KLT)是直接由操作系统内核(Kernel,内核)支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器(Scheduler)对线程进行调度,并负责将线程的任务映射到各个处理器上。每个内核线程可以视为内核的一个分身(孙悟空的分身术?),这样操作系统就有能力同时处理多件事情,支持多线程的内核就叫做多线程内核(Muti-Threads Kernel)。

    Java程序如何使用内核线程:

    程序一般通过使用内核线程的高级接口-----轻量级进程(Light Weight Process, LWP),也就是我们通常意义上的线程。每个LWP都由一个内核线程支持。也就是说任何时候使用Java代码创建线程,调用Thread.start()的时候,都是通过LWP接口创建了KLT内核线程,然后通过OS的Thread Scheduler对内核线程进行调度分配CPU。线程模型如下图所示:

    内核线程的优点:

    (1)每一个内核线程都是独立的轻量级进程,一个线程的阻塞不会影响整个进程的工作。

    内核线程的缺点:

    (1)由于是基于内核线程实现,各种线程的操作,如创建、析构、中断、休眠和同步,都需要系统调度(频繁从用户态切换进内核态),而系统调度的代价相对较高;

    (2)占用内核资源,同时轻量级进程的数量有限。

    Thread线程运行在Java Virtual Machine中,要理解Java中线程的运行方式,得先了解Java内存模型。Java虚拟机规范中定义了一种Java内存模型(Java Memory Model)来屏蔽各种硬件和操作系统的内存访问差异,以实现Java程序在各种平台下都能达到一致的内存访问效果(一次编译,随处运行得以实现的基础)。

    主内存与工作内存:

    JAVA内存模型规定了所有的变量都存储在主内存(Main Memory)中。所有的线程都有自己的工作内存,工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中执行,而不能直接读写主内存中的变量。同时,线程之间也无法读写各自的工作内存。关系图:

    线程状态转换图:

    Thread#yield():

    执行此方法会向系统线程调度器(Schelduler)发出一个暗示,告诉其当前JAVA线程打算放弃对CPU的使用,但该暗示,有可能被调度器忽略。使用该方法,可以防止线程对CPU的过度使用,提高系统性能。

    Thread#sleep(time)或Thread.sleep(time, nanos):

    使当前线程进入休眠阶段,状态变为:TIME_WAITING

    Thread.interrupt():

    中断当前线程的执行,允许当前线程对自身进行中断,否则将会校验调用方线程是否有对该线程的权限。

    如果当前线程因被调用Object#wait(),Object#wait(long, int), 或者线程本身的join(), join(long),sleep()处于阻塞状态中,此时调用interrupt方法会使抛出InterruptedException,而且线程的阻塞状态将会被清除。

    Thread#interrupted(),返回true或者false:

    查看当前线程是否处于中断状态,这个方法比较特殊之处在于,如果调用成功,会将当前线程的interrupt status清除。所以如果连续2次调用该方法,第二次将返回false。

    Thread.isInterrupted(),返回true或者false:

    与上面方法相同的地方在于,该方法返回当前线程的中断状态。不同的地方在于,它不会清除当前线程的interrupt status状态。

    Thread#join(),Thread#join(time):

    A线程调用B线程的join()方法,将会使A等待B执行,直到B线程终止。如果传入time参数,将会使A等待B执行time的时间,如果time时间到达,将会切换进A线程,继续执行A线程。

    展开全文
  • Java Thread类的 yield()、join()

    万次阅读 2014-08-16 22:34:30
    final Thread thread1 = new Thread() { public void run() { System.out.println("first"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }...

    yield:

    解释它之前,先简述下,多线程的执行流程:多个线程并发请求执行时,由cpu决定优先执行哪一个,

    即使通过thread.setPriority(),设置了线程的优先级,也不一定就是每次都先执行它

        yield,表示暂停当前线程,执行其他线程(包括自身线程) 由cpu决定

    public class TestYield implements Runnable {  
    	  
    		public void run() {  
    
    				System.out.println("first: " + Thread.currentThread().getName() );  
    				// 暂停当前正在执行的线程对象,并执行其他线程,就是进入就绪状态  
    				Thread.currentThread().yield();  
    				// 可能还会执行 本线程: 以下语句不一定紧接着上面的语句被执行,可能其他线程的先执行了
    				System.out.println("second: " + Thread.currentThread().getName() );  
    
    		}  
    	  
    		public static void main(String[] args) {  
    			TestYield runn = new TestYield();  
    			Thread t1 = new Thread(runn);  
    			Thread t2 = new Thread(runn);  
    			Thread t3 = new Thread(runn);  
    			  
    			t2.setPriority(t2.getPriority()+1); //设置t2的线程优先级 
    			t1.start();  
    			t2.start();  
    			t3.start();  
    	  
    		}  
    }  

    多次运行,看运行结果

    某一次:

    first: Thread-0
    first: Thread-2
    second: Thread-2
    first: Thread-1
    second: Thread-0
    second: Thread-1
    再一次:

    first: Thread-1
    first: Thread-2
    first: Thread-0
    second: Thread-2
    second: Thread-1
    second: Thread-0

    其实默认情况下,多线程时,cpu就会切换执行的任务线程,而yield方法,只是人为的通知系统,进行切换,

    且有一定机率能切换回本身



    join:

    阻塞所在线程,等调用它的线程执行完毕,再向下执行

    public class TestJoin {  
    	  
    	public static void main(String[] args) throws InterruptedException {
    
    		final Thread thread1 = new Thread() {
    			public void run() {
    				System.out.println("first");
    				try {
    					Thread.sleep(500);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				System.out.println("second");
    			};
    		};
    		thread1.start();
    //		thread1.join();		//在这阻塞主线程main
    		
    		Thread thread2 = new Thread() {
    			public void run() {
    				try {
    					System.out.println("third");
    //					thread1.join(); // 等待t1线程 执行完结,才继续向下执行	在这阻塞子线程thread2
    
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("fourth");
    			};
    		};
    		thread2.start();
    	}
    }  

    > 当没有打开相关的join调用代码时,『third、fourth』应该会优先于『second』进行输出

    > 当仅打开主线程中的join调用代码时,则会阻塞主线程,thread2要等待thread1执行完后再执行,则会输出:

    first
    second
    third
    fourth
    

    > 当仅打开thread2中的join调用代码时,则会阻塞thread2,则会输出:

    first
    third
    second
    fourth


    展开全文
  • Java Thread

    千次阅读 2005-03-11 09:07:00
    A thread is a single sequential...Java通过java.lang.Thread类来支持多线程。在Thread类中封装了独立的有关线程执行的数据和方法,并将多线程与面向对象的结构合为一体。Java提供了两种方法创建线程,一种是继承Threa

    A thread is a single sequential flow of control within a program.(线程是一个进程中一段独立的控制流)。一个进程可以拥有若干个线程。Java通过java.lang.Thread类来支持多线程。在Thread类中封装了独立的有关线程执行的数据和方法,并将多线程与面向对象的结构合为一体。

    Java提供了两种方法创建线程,一种是继承Thread类并重写run方法,另一种则是实现接口Runnable

    继承Thread

    import java.lang.Thread;

    import java.lang.Math;

    import java.lang.InterruptedException;

    public class SimpleThread extends Thread {

        //构造函数,设置线程的名字。否则自动生成的名字格式为 "Thread-"+n, n是整数。

        public SimpleThread(String str) {

            super(str);

        }

        public void run() {

            for (int i = 0; i < 10; i++) {

                System.out.println(i + " " + getName());

                try {

                    //sleep

                    sleep((long)(Math.random() * 1000));

                } catch (InterruptedException e) {}

            }

            System.out.println("DONE! " + getName());

        }

    }

     

    //Threadstart方法

    public native synchronized void start()

    使该线程开始执行; Java 虚拟机调用线程 run 方法。

    结果是两个线程同时运行: 当前线程 (方法 start 返回的线程) 和另一个线程 (执行方法 run 的线程)

     

    //Threadrun方法

    public void run()

    如果该线程是用不同的Runnable运行对象构造的, 则该Runnable对象的run方法被调用; 否则, 该方法不做任何事就返回。

    Thread 的子类必须覆盖此方法。

    抛出: IllegalThreadStateException如果该线程已经启动。

     

    虽然run()函数实现了多个线程的并行处理,但不能直接调用run()函数,而是通过调用start()函数来调用run()函数。在调用start()的时候,start()函数会首先进行与多线程相关的初始化(这也是为什么不能直接调用run()函数的原因),然后再调用run()函数。

    public class TwoThreadsDemo {

        public static void main (String[] args) {

            new SimpleThread("Jamaica").start();

            new SimpleThread("Fiji").start();

        }

    }

    实现接口Runnable

        如果有一个类,它已继承了某个类,又想实现多线程,那就可以通过实现Runnable接口来实现。

        1) Runnable接口只有一个run()函数。

        2) 把一个实现了Runnable接口的对象作为参数产生一个Thread对象,再调用Thread对象的start()函数就可执行并行操作。如果在产生一个Thread对象时以一个Runnable接口的实现类的对象作为参数,那么在调用start()函数时,start()会调用Runnable接口的实现类中的run()函数。

    import java.lang.Thread;

    import java.lang.System;

    import java.lang.Math;

    import java.lang.InterruptedException;

    import java.lang.Runnable;

    class MyThread implements Runnable{

        String name;

        private Thread myThread = null;

        public MyThread(String name){

          this.name = name;

        }

        public void start() {

            if (myThread == null) {

                myThread = new Thread(this, "Clock");

                myThread.start();

            }

        }

        public void run(){

            Thread curThread = Thread.currentThread();

            if (curThread == myThread) {

                for (int i = 0; i < 10; i++) {

                    System.out.println(i + " " + getName());

                    try {

                        //sleep

                        //接口Runnable中没有方法sleep()

                        Thread.sleep(1000);

                    } catch (InterruptedException e) {}

                }

                System.out.println("DONE! " + getName());

            }

        } 

    }

    总结:

    两种提供线程run方法的途径:

    1. 继承java.lang.Thread类并重写run方法

    2. 实现java.lang.Runnable接口并实现run方法

    如果类是从其它类继承下来的,则应该选用实现java.lang.Runnable接口的方法

     

    若干常用的方法

    currentThread()              这是一个类方法,返回当前正在执行的线程。

    isAlive()                    判别一个线程是否仍然活着,包括这个线程正在执行或有机会被执行。返回一个布尔值。

    suspend()                  悬挂起某个线程,并使得这个线程只可被resume()方法激活。

    resume()                   suspend()配合使用。唤醒线程。

    yeild()                       强迫线程交出执行权利供其它线程使用。

    stop()                       使线程进入死亡(dead)状态。

     

    线程的生命周期

    ●新线程态(New Thread)

        当用new方法创建一个线程对象后,它仅仅是一个空的线程对象,没有分配有任何系统资源。当线程处于该状态时,只能只能启动或终止它任何其他操作都会引发IllegalThreadStateException异常

     

    ●可运行态(Runnable)    start()方法产生运行线程所必须的资源,调度线程执行,并且调用线程的run()方法。在这时线程处于可运行态。该状态不称为运行态是因为这时的线程并不总是一直占用处理机。特别是对于只有一个处理机的PC而言,任何时刻只能有一个处于可运行态的线程占用处理 机。Java通过调度来实现多线程对处理机的共享。

     

    ●非运行态(Not Runnable)

    当下面的任何一个情况发生时,线程进入不可运行状态

    A thread becomes Not Runnable when one of these events occurs:

    1) If a thread has been put to sleep, then the specified number of milliseconds must elapse.(sleep()方法被调用)

    2) suspend()方法被调用;

    3) The thread calls the wait method to wait for a specific condition to be satisifed. (线程使用wait()来等待条件变量)

    4) The thread is blocking on I/O. (线程处于I/O等待)

     

    在第三种情况发生时,线程处于等待状态(等待某个能使它返回可运行状态的事件发生)即使处理器空闲,线程也无法运行。当可使线程返回运行状态的条件满足时,线程处于可运行状态,一旦处理器可用,线程将会再次运行。(例如被方法suspend()挂起的进程就要等待方法resume()方可被唤醒)

    For each entrance into the Not Runnable state, there is a specific and distinct escape route that returns the thread to the Runnable state. An escape route works only for its corresponding entrance. For example, if a thread has been put to sleep, then the specified number of milliseconds must elapse before the thread becomes Runnable again. The following list describes the escape route for every entrance into the Not Runnable state:

    (对每一个进入非运行状态的入口,都有一个特殊且明确的回路返回到线程的可运行状态。该回路紧紧为对应的入口工作。例如一个线程sleep,必须经过一段时间后才能返回可运行状态。以下的列表描述每一个进入非运行状态入口对应的回路)

    If a thread has been put to sleep, then the specified number of milliseconds must elapse.(如果线程sleep,必须等待设定的时间)

    If a thread is waiting for a condition, then another object must notify the waiting thread of a change in condition by calling notify or notifyAll. More information is available in Synchronizing Threads. (如果线程等待条件,那么其它的对象必须通过改变条件来通知等待的线程)

    If a thread is blocked on I/O, then the I/O must complete. (如果线程处于I/O等待,则I/O操作必须完成)

     

    ●死亡态(Dead)

    run()方法返回,或别的线程调用stop()方法,线程进入死亡态 。通常Applet使用它的stop()方法来终止它产生的所有线程。

     

    The isAlive Method

    如果线程已经运行并且没有停止则isAlive方法返回true. 如果isAlive方法返回false,则表示该线程可能是一个新线程或者是进入死亡状态。如果isAlive方法返回true,线程既可以是可运行的也可以是不可运行的。因此不能通过isAlive区分新线程和死亡状态的线程,只能区分可运行线程和不可运行线程

     

    线程的同步

    生产者/消费者模型

    如果一个线程为另一个提供服务,那么我们把提供服务的线程称为生产者(Producer),另外一个线程称为消费者(consumer)

    假设生产者产生0-9的整数并存储在一个公共对象CubbyHole中,消费者从CubbyHole对象中获取生产者生成的整数并打印出来。假定生产者线程每生产一个数都会sleep一段随机时间。

        Class CubbyHole {

            private int contents;

            public int get() {

                return contents;

            }

            public void put(int contents) {

                this.coutents = contents;

            }

        }

     

        //Producer

        Class Producer extends Thread {

            private Cubbyhole hole;

            public Producer(Cubbyhole hole) {

                this.hole = hole;

            }

            public void run() {

                for (int i=0; i<10; i++) {

                    hole.put(i);

                    try {

                        sleep((long)(Math.random()*100));

                    } catch (InterruptedException ex) {

                        System.out.println("Thread Interrupted");

                        System.out.println(ex.getStackTrace());

                    }

                }

            }

        }

     

        //Consumer

        public class Consumer extends Thread {

            private Cubbyhole hole;

            public Consumer(Cubbyhole hole){

                this.hole = hole;

            }

            public void run() {

                for (int i=0; i<10; i++) {

                    System.out.println(hole.get());

                }

            }

        }

    在本例中生产者(Producer)和消费者(Consumer)共享公共的资源--CubbyHole对象。在上述程序中,同步问题将会发生在ProducerConsumer线程之间。如果Producer生成数据速度大于Consumer获取速度或者是Consumer获取速度大于Producer生产速度,Consumer获取的结果都是错误的。实际上,我们需要的是Consumer所取得的数据是Producer每一次生成的数据。

    ProducerConsumer的活动在两个方法必须是同步的。

    首先,该两个线程必须不能同时访问Cubbyhole对象。在Java线程中可以通过锁定对象来防止该情况发生。当一个对象被一个线程锁定后,第二个线程试图调用该对象的同步方法,则第二个线程将会被阻塞,直到对象被解除锁定。

    其次,该两个线程必须做一些简单的合作。也就是说,Producer必须通过某种方法通知Consumer数据已经准备好而Consumer必须告诉Producer数据已经被获取了。线程类提供wait,notifynotifyAll方法帮助线程等待条件并当条件改变时通知其它线程

     

    锁定对象

    临界区(critical sections)

    The code segments within a program that access the same object from separate, concurrent threads are called critical sections. java critical section 可以是一个block或者是用synchronized关键字标识的方法。

    Producer/consumer例子中,Producer改变Cubbyhole对象时,Consumer不可以访问CubbyHole对象;当Consumer读取CubbyHole对象时Producer不可以改变CubbyHole对象。因此Cubbyhole对象的putget方法都应该声明为critical sections.

    public class CubbyHole {

        private int contents;

        private boolean available = false;

        public synchronized int get() {

            ...

        }

        public synchronized void put(int value) {

            ...

        }

    }

    无论什么时候当一个线程进入一个同步方法,其它线程都不能调用该对象的同步方法,直到对象解锁为止。因此当Producer调用put方法时,Cubbyhole对象被锁定,防止Consumer调用Cubbyholeget方法。当put方法返回后,Coubbyhole对象被解锁。

    public synchronized int get() {

        // CubbyHole locked by the Consumer

        ...

        // CubbyHole unlocked by the Consumer

    }

    锁和解锁都是通过java运行系统自动实现的,以保证数据的完整性。然而仅仅依靠同步还不行,两个线程之间必须相互通知对方各自的工作已经完成。

     

    notifyAllwait方法

    Cubbyhole对象中加入一私有布尔值成员变量available.availabletrue时,允许获取数据;为false时允许写入数据。简单实现如下:

    public synchronized int get() {

        if (available == true) {

            available = false;

            return contents;

        }

    }

    public synchronized void put(int value) {

        if (available == false) {

            available = true;

            contents = value;

        }

    }

    实际情况下以上两个方法不会正常工作。当Producer还没有生产数据时,此时available不可能为true.同样地,ProducerConsumer取得数据之前调用put方法,则put方法什么都没有做。因此Consumer必须等待Producer把数据放入到CubbyHole中并通知Consumer已放入数据。同样地,Producer必须等待直到Consumer取走数据并通知它才能放入新的数据到CubbyHole中。该两个线程可以通过对象的waitnotifyAll方法来完成。putget方法修改如下:

    public synchronized int get() {

        while (available == false) {

            try {

                // wait for Producer to put value

                wait();

            } catch (InterruptedException e) {

            }

        }

        available = false;

        // notify Producer that value has been retrieved

        notifyAll();

        return contents;

    }

    public synchronized void put(int value) {

        while (available == true) {

            try {

                // wait for Consumer to get value

                wait();

            } catch (InterruptedException e) {

            }

        }

        contents = value;

        available = true;

        // notify Consumer that value has been set

        notifyAll();

    }

     

    get方法中,一直循环直到Producer生成一个数,每一次循环都调用wait方法。wait方法放弃锁Cubbyhole对象,允许Producer锁定并更新CubbyHole对象,并等待Producer的通知。当Producer更新CubbyHole对象后,调用notifyAll方法通知Consumer.然后Consumer退出wait状态,availabletrue,退出循环,get方法返回值。同样地,put方法等待Consumer线程获取当前值

    notifyAll方法唤醒所有等待同一对象(CubbyHole)的进程,被唤醒的进程竞争,一个线程获得锁后,其他线程返回等待。对象类也可以定义notify方法指定唤醒某一等待的线程

     

    Java在类java.lang.Object中定义了wait()notify()方法,调用它们也可以实现线程之间的同步。

    要点:可以用sleep方法替代wait方法。但wait方法可以通过notify方法唤醒而sleep必须要等到特定时间过后才能唤醒。

         public final void wait(long millseconds) throws InterruptedException

    调用此方法时,被调对象进入等待状态,直到被唤醒或等待时间到。

    public final void notify()                        唤醒一个对象内处于等待状态的对象。

    public find void Allotify()                       唤醒一个对象内所有处于等待状态的对象。

    线程优先级与调度

      由于我们一般使用的计算机是单CPU的,所以在执行多线程程序时需进行线程调度。线程调度是由线程的优先级决定的。高优先级的线程总是先运行的。Java采用的是抢占式(preemptive)的调度方式,即当高优先级的线程进入可运行(runnable)状态时,会抢占低优先级的线程的位置,并开始执行。当同时有两个或两个以上的线程具有高优先级并进入可运行状态,Java的调度会自动在这些线程间交替调度执行。

      在Java中,Thread类中预定义了三个常量:

      MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY,

      一个线程的优先级应在MAX_PRIORITYMIN_PRIORITY之间。NORM_PRIORITY是缺省的优先级值,一般是MIN_PRIORITYMAX_PRIORITY的平均值。

      在Java中,Thread类提供了方法设置和获取优先级。

      setPriority(int)  用于设置线程的优先数

      setPriority()   用于获取线程的优先数

     

    线程组(Thread Group)

      线程组是包括了许多线程的对象集。每个线程有自己特定的线程组。一个线程在创建时就属于某个线程组,直至其执行结束,此线程不可更改其所属的线程组。Thread类中提供了构造方法使创建线程时同时决定其线程组。Thread类总共提供了六种构造方法:

      Thread();

      Thread(String);

      Thread(Runnable);

      Thread(Runnable,String);

      Thread(ThreadGroup,String);

      Thread(ThreadGroup,Runnable,String);

      前四种缺省了线程组,表示所创建的线程属于main线程组,后两种则指定了所创建的线程的线程组。线程可以访问自己所在的线程组,但不能访问本线程组的父类。对线程组进行操作就是对线程组中的各个线程同时进行操作。

      线程组的构造方法:

      ThreadGroup(String groupName)

    创建名为groupName的线程组,该线程组的父类为当前线程所在程组。

      ThreadGroup(ThreadGroup parent,String groupName)

    创建名为groupName的线程组,该线程组的父类是parent

     

    ------------------------------------------------------------多线程要点----------------------------------------------------------------------------

    1.多线程中有主内存和工作内存之分, JVM中,有一个主内存,专门负责所有线程共享数据;而每个线程都有他自己私有的工作内存, 主内存和工作内存分贝在JVMstack区和heap区。

    2.线程的状态有'Ready', 'Running', 'Sleeping', 'Blocked', 'Waiting'几个状态

    3.线程运行次序并不是按照我们创建他们时的顺序来运行的,CPU处理线程的顺序是不确定的,如果需要确定,那么必须手工介入,使用setPriority()方法设置优先级。

    4.我们无从知道一个线程什么时候运行,两个或多个线程在访问同一个资源时,需要synchronized

    5. 每个线程会注册自己,实际某处存在着对它的引用,因此,垃圾回收机制对它就“束手无策”了。

     

    6. Daemon线程区别一般线程之处是:主程序一旦结束,Daemon线程就会结束。

    7. 一个对象中的所有synchronized方法都共享一把锁,这把锁能够防止多个方法对通用内存同时进行的写操作。synchronized static方法可在一个类范围内被相互间锁定起来。

    8. 对于访问某个关键共享资源的所有方法,都必须把它们设为synchronized,否则就不能正常工作。

    9. 假设已知一个方法不会造成冲突,最明智的方法是不要使用synchronized,能提高些性能。

    10. 如果一个"同步"方法修改了一个变量,而我们的方法要用到这个变量(可能是只读),最好将自己的这个方法也设为 synchronized

     

    11. synchronized不能继承, 父类的方法是synchronized,那么其子类重载方法中就不会继承“同步”。

    12. 线程堵塞Blocked有几个原因造成:

    (1)线程在等候一些IO操作

    (2)线程试图调用另外一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。

    13.原子型操作(atomic), 对原始型变量(primitive)的操作是原子型的atomic. 意味着这些操作是线程安全的, 但是大部分情况下,我们并不能正确使用,来看看 i = i + 1 , iint型,属于原始型变量:


    (1)从主内存中读取i值到本地内存.

    (2)将值从本地内存装载到线程工作拷贝中.

    (3)装载变量1.

    (4)i 1.

    (5)将结果给变量i.

    (6)i保存到线程本地工作拷贝中.

    (7)写回主内存.


    注意原子型操作只限于第1步到第2步的读取以及第6到第7步的写, i的值还是可能被同时执行i=i+1的多线程中断打扰(在第4)double long 变量是非原子型的(non-atomic)。数组是object 非原子型。

    14. 由于13条的原因,我们解决办法是:

    class xxx extends Thread{

    //i会被经常修改

    private int i;

    public synchronized int read(){ return i;}

    public synchronized void update(){ i = i + 1;}

        ..........

    }

    15. Volatile变量, volatile变量表示保证它必须是与主内存保持一致,它实际是"变量的同步", 也就是说对于volatile变量的操作是原子型的,如用在long double变量前。

     

    16. 使用yield()会自动放弃CPU,有时比sleep更能提升性能。

    17. sleep()wait()的区别是:wait()方法被调用时会解除锁定,但是我们能使用它的地方只是在一个同步的方法或代码块内。

    18. 通过制造缩小同步范围,尽可能的实现代码块同步,wait(毫秒数)可在指定的毫秒数可退出wait;对于wait()需要被notisfy()notifyAll()踢醒。

    19. 构造两个线程之间实时通信的方法分几步:

    (1). 创建一个PipedWriter和一个PipedReader和它们之间的管道;

    PipedReader in = new PipedReader(new PipedWriter())

    (2). 在需要发送信息的线程开始之前,将外部的PipedWriter导向给其内部的Writer实例out

    (3). 在需要接受信息的线程开始之前,将外部的PipedReader导向给其内部的Reader实例in

    (4). 这样放入out的所有东西度可从in中提取出来。

    20. synchronized带来的问题除性能有所下降外,最大的缺点是会带来死锁DeadLock,只有通过谨慎设计来防止死锁,其他毫无办法,这也是线程难以驯服的一个原因。不要再使用stop() suspend() resume()destory()方法

     

    21. 在大量线程被堵塞时,最高优先级的线程先运行。但是不表示低级别线程不会运行,运行概率小而已。

    22. 线程组的主要优点是:使用单个命令可完成对整个线程组的操作。很少需要用到线程组。

    23. 从以下几个方面提升多线程的性能:

    检查所有可能Block的地方,尽可能的多的使用sleepyield()以及wait();

    尽可能延长sleep(毫秒数)的时间;

    运行的线程不用超过100个,不能太多;

    展开全文
  • Java抽象 详解

    万次阅读 多人点赞 2016-10-05 00:06:35
    一、抽象的基本概念普通是一个完善的功能,可以直接产生实例化对象,并且在普通中可以包含有构造方法、普通方法、static方法、常量和变量等内容。而抽象是指在普通的结构里面增加抽象方法的组成部分。...
  • Java学习笔记-Thread类

    千次阅读 2019-07-08 22:04:51
    java.lang.Thread ,API中该中定义了有关线程的一些方法,具体如下: 构造方法: public Thread() :分配一个新的线程对象。 public Thread(String name) :分配一个指定名字的新的线程对象。 public Thread...
  • Java Thread 总结

    万次阅读 2013-02-28 19:18:44
    这篇文章的主要内容来自于网络,由我来整理,姑且算是原创吧,但是对于内容的提供者,在此表示感谢。 1.线程概述 线程是一个程序的多个执行路径,执行调度的单元,依托于进程的存在。...Java中的多线程是一个抢占
  • Java内部

    千次阅读 2018-12-28 11:21:17
    Java内部真的很难理解,但有必要搞懂,因为内部让外部更丰富多彩了,就好像一个人的心中还可以住着另外一个人。
  • Java 并发:Thread 深度解析

    万次阅读 多人点赞 2017-01-11 20:44:31
     JavaThread类 的各种操作与线程的生命周期密不可分,了解线程的生命周期有助于对Thread类中的各方法的理解。一般来说,线程从最初的创建到最终的消亡,要经历创建、就绪、运行、阻塞 和 消亡 五个状态。在线程...
  • Java Thread 用法实例

    万次阅读 2011-01-06 10:59:00
    JAVA多线程机制有两种实现方式: 第一种:继承Thread类, 实现run()方法; 第二种:实现Runnable接口。 Thread 类的常用函数及功能
  • javaThread类的join方法

    千次阅读 2017-11-13 13:21:03
    那么我们如何实现让线程T1,T2,T3,在T1执行完成后才执行T2,T2执行完成后才执行T3,也就是线程的串行化,通过Thread类的join方法就可以实现。 join方法:将该线程加入当前线程,当前线程等待加入线程执行完成...
  • Java Thread 实现方式

    千次阅读 2018-05-09 08:45:45
    答案是调用run()的线程,因为只有在调用start()之后,Java才会创建一个新的线程,然后新的线程再调用执行Java代码里面的run()。看如下代码,一个简单的实现:Thread thread = new Thread(){ public...
  • java thread synchronized 理解

    千次阅读 2009-12-18 14:05:00
    Java Thread 用起来并不难,但往往还是容易出错。 我们知道 synchronized 关键字主要是防止多线程访问共享资源。下面是个简单的测试,关于synchronized 使用。 /** * @author gaofeng * @date 2009-12-18 */public...
  • Java中使用Thread类

    千次阅读 2018-07-17 15:12:45
    Java的特点之一就是内置对多线程的支持。 每个Java程序都有一个默认的主线程main。如果main方法中又创建了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源,main方法即使...
  • Java Thread 那些事

    千次阅读 2013-12-12 12:56:13
    这篇文章被压在草稿箱许久,最近公司内部的技术社区有同学贴出了几篇分享Java线程的文章,发觉有很多概念没有讲清楚,所以花点时间继续撰写,便有了这篇博文。本文只聚焦JVM层面的线程模型,不考虑和真实的操作系统...
  • 1. 前言线程与进程的理解详见:https://blog.csdn.net/qq_38969070/article/details/80424079多线程处理(Multithreaded execution)是Java平台的基本特征:(1) 每个应用至少有一个线程。(2) 从程序员的角度...
  • return currentThread().isInterrupted(true); } public boolean isInterrupted() { return isInterrupted(false); } public void interrupt() { if (this != Thread.currentThread()) checkAccess(); ...
  • 深入理解Java类加载器(ClassLoader)

    万次阅读 多人点赞 2017-06-26 09:34:08
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ...深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解
  • if(Thread.currentThread().isInterrupted()){ //如果当前线程已经被设置了中断标志位,则返回true System.out.println("Interrupted"); break; } try { Thread.currentThread().sleep(1000); } catch ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 575,001
精华内容 230,000
关键字:

javathread类

java 订阅