스레드는 프로그램의 실행 스레드입니다. Java 가상 머신을 사용하면 애플리케이션이 여러 스레드를 동시에 실행할 수 있습니다.
각 스레드에는 우선순위가 있으며 우선순위가 높은 스레드의 실행이 우선순위가 낮은 스레드보다 우선합니다. 각 스레드는 데몬으로 표시되거나 표시되지 않을 수 있습니다. 스레드에서 실행되는 코드가 새 Thread 개체를 생성하면 새 스레드의 초기 우선순위는 생성 스레드의 우선순위로 설정되고, 생성 스레드가 데몬 스레드인 경우에만 새 스레드는 데몬입니다.
Java Virtual Machine이 시작되면 일반적으로 데몬이 아닌 단일 스레드가 있습니다(일반적으로 지정된 클래스의 기본 메서드를 호출합니다). Java Virtual Machine은 다음 조건 중 하나가 발생할 때까지 스레드를 계속 실행합니다.
1. Runtime 클래스의 종료 메소드가 호출되고 보안 관리자가 종료 작업이 발생하도록 허용합니다.
2. 데몬 스레드가 아닌 모든 스레드는 run 메서드 호출에서 반환되거나 run 메서드 외부로 전파되는 예외를 발생시켜 실행을 중지했습니다.
스레드를 구현하는 방법은 다음 장에서 소개하겠습니다
소스 코드 참조는 다음과 같습니다.
/** * A <i>thread</i> is a thread of execution in a program. The Java * Virtual Machine allows an application to have multiple threads of * execution running concurrently. * <p> * Every thread has a priority. Threads with higher priority are * executed in preference to threads with lower priority. Each thread * may or may not also be marked as a daemon. When code running in * some thread creates a new <code>Thread</code> object, the new * thread has its priority initially set equal to the priority of the * creating thread, and is a daemon thread if and only if the * creating thread is a daemon. * <p> * When a Java Virtual Machine starts up, there is usually a single * non-daemon thread (which typically calls the method named * <code>main</code> of some designated class). The Java Virtual * Machine continues to execute threads until either of the following * occurs: * <ul> * <li>The <code>exit</code> method of class <code>Runtime</code> has been * called and the security manager has permitted the exit operation * to take place. * <li>All threads that are not daemon threads have died, either by * returning from the call to the <code>run</code> method or by * throwing an exception that propagates beyond the <code>run</code> * method. * </ul> * <p> * There are two ways to create a new thread of execution. One is to * declare a class to be a subclass of <code>Thread</code>. This * subclass should override the <code>run</code> method of class * <code>Thread</code>. An instance of the subclass can then be * allocated and started. For example, a thread that computes primes * larger than a stated value could be written as follows: * <hr><blockquote><pre class="brush:php;toolbar:false"> * class PrimeThread extends Thread { * long minPrime; * PrimeThread(long minPrime) { * this.minPrime = minPrime; * } * * public void run() { * // compute primes larger than minPrime * . . . * } * } *
* The following code would then create a thread and start it running: *
** PrimeThread p = new PrimeThread(143); * p.start(); *
* The other way to create a thread is to declare a class that
* implements the Runnable
interface. That class then
* implements the run
method. An instance of the class can
* then be allocated, passed as an argument when creating
* Thread
, and started. The same example in this other
* style looks like the following:
*
* class PrimeRun implements Runnable { * long minPrime; * PrimeRun(long minPrime) { * this.minPrime = minPrime; * } * * public void run() { * // compute primes larger than minPrime * . . . * } * } *
* The following code would then create a thread and start it running: *
** PrimeRun p = new PrimeRun(143); * new Thread(p).start(); *
* Every thread has a name for identification purposes. More than * one thread may have the same name. If a name is not specified when * a thread is created, a new name is generated for it. *
* Unless otherwise noted, passing a {@code null} argument to a constructor * or method in this class will cause a {@link NullPointerException} to be * thrown. * * @author unascribed * @see Runnable * @see Runtime#exit(int) * @see #run() * @see #stop() * @since JDK1.0 */ publicclass Thread implements Runnable {
스레드를 실행하기 전에 먼저 스레드 객체를 생성해야 합니다. 스레드가 속한 스레드 그룹, 스레드 우선순위, 데몬 스레드인지 여부 등 스레드에 필요한 속성을 제공합니다. 새 Thread에서는 Thread 개체를 인스턴스화하기 위해 다음 메서드가 호출됩니다. 초기화 코드는 다음과 같습니다.
/** * 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 */ private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) { 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; //设置daemon 、priority 属性为父线程对应的值 this.daemon = parent.isDaemon(); 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); //将父线程的InheritableThreadLocal复制过来 if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ //生成线程id(一个long型的字段threadSeqNumber) tid = nextThreadID(); }
에 스레드 ID를 할당합니다. 실행 가능한 스레드 개체는 초기화 작업을 완료하고 힙 메모리에서 실행되기를 기다리고 있습니다. 빌드 방법
//方法1通过继承Thread实现class MyThread extends Thread{ //需要实现的方法,该方法执行具体的业务逻辑 @Override public void run() { System.out.println(Thread.currentThread().getName() +" @@@@ MyThread。run()我是通过继承Thread实现的多线程"); } }
의 start() 인스턴스 메서드를 이용하는 것입니다. start() 메서드는 새 스레드를 시작하고 run() 메서드를 실행하는 기본 메서드입니다. 이러한 방식으로 멀티스레딩을 구현하는 것은 매우 간단합니다. 자신의 클래스를 통해 Thread를 직접 확장하고 run() 메서드를 재정의하면 새 스레드를 시작하고 자신이 정의한 run() 메서드를 실행할 수 있습니다. run() 메서드의 메서드 본문은 스레드가 완료해야 하는 작업을 나타내며, 이를
스레드 실행 본문이라고 합니다. 이 스레드 클래스 개체가 생성되면 새 스레드가 생성되고 스레드 새 상태로 들어갑니다. 스레드 객체가 참조하는 start() 메서드를 호출하면 스레드가 준비 상태로 진입합니다. 이때 CPU 스케줄링 타이밍에 따라 스레드가 즉시 실행되지 않을 수도 있습니다. 인터페이스 Runnable 구현
//方法2通过实现runnable接口 //实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例, //并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。class MyRunnable implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+ " @@@@ MyRunnable。run()我是通过实现Runnable接口实现的多线程"); } }
스레드 풀 인터페이스 ExecutorService와 결합하면 반환된 결과로 전설적인 멀티스레딩을 실현할 수 있습니다. Executor의 사용법은 다음 글에서 자세히 소개하겠습니다. //方法3通过Executor框架实现class MyCallable implements Callable<Integer>{
//需要实现call方法而不是run方法
@Override public Integer call() throws Exception { return 100;
}
}
스레드 시작
Start 메소드 소스코드 설명은 다음과 같습니다.
/** * Causes this thread to begin execution; the Java Virtual Machine * calls the <code>run</code> method of this thread. * <p> * The result is that two threads are running concurrently: the * current thread (which returns from the call to the * <code>start</code> method) and the other thread (which executes its * <code>run</code> method). * <p> * It is never legal to start a thread more than once. * In particular, a thread may not be restarted once it has completed * execution. * * @exception IllegalThreadStateException if the thread was already * started. * @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 */ } } } private native void start0();
public class TestCreateThread { public static void main(String[] args) { Thread myThread = new MyThread(); myThread.setName("myThread"); myThread.start(); Runnable myRunnable = new MyRunnable(); Thread myRunnableThread = new Thread(myRunnable); myRunnableThread.setName("myRunnableThread"); myRunnableThread.start(); Thread myRunnableThread2 = new MyThread(myRunnable); myRunnableThread2.setName("myRunnableThread2"); myRunnableThread2.start(); //执行结果参考如下: //myThread @@@@ MyThread。run()我是通过继承Thread实现的多线程 //myRunnableThread2 @@@@ MyThread。run()我是通过继承Thread实现的多线程 //myRunnableThread @@@@ MyRunnable。run()我是通过实现Runnable接口实现的多线程 //测试callable方法 // 创建MyCallable对象 Callable<Integer> myCallable = new MyCallable(); //使用FutureTask来包装MyCallable对象 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //FutureTask对象作为Thread对象的target创建新的线程 Thread thread = new Thread(ft); thread.start();//启用 //获取信息 try { //取得新创建的新线程中的call()方法返回的结果 //当子线程此方法还未执行完毕,ft.get()方法会一直阻塞, //直到call()方法执行完毕才能取到返回值。 int sum = ft.get(); System.out.println("sum = " + sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //使用ExecutorService处理多线程 ExecutorService pool = Executors.newFixedThreadPool(10); Future<Integer> f = pool.submit(myCallable); // 关闭线程池 pool.shutdown(); try { int sum1 = f.get(); System.out.println("sum1 = " + sum1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
无论何种方式,启动一个线程,就要给它一个名字!这对排错诊断系统监控有帮助。否则诊断问题时,无法直观知道某个线程的用途。
Thread实现接口Runnable,并且实现了run方法,代码参考如下:
//如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法; //否则,该方法不执行任何操作并返回。 //Thread 的子类应该重写该方法。 /** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * <p> * Subclasses of <code>Thread</code> should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ @Override public void run() { if (target != null) { target.run(); } } }
当执行到Thread类中的run()方法时,会首先判断target是否存在,存在则执行target中的run()方法,也就是实现了Runnable接口并重写了run()方法的类中的run()方法。当时如果该Runnable的子类是通过一个继承Thread的子类(该且重写了run方法),则真正执行的是Thread子类重写的run方法(由于多态的原因)。
위 내용은 Java 동시성 스레드 사용 및 시작 스레드 구축의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!