public static void main(String[] args){ add(); remove(); get(); System.out.println(222); } public static void add(){ // 一万次循环 } public static void remove(){ } public static void get(){ }
大部分操做系统都支持多进程并发运行,如今的操做系统几乎都支持同时运行多个程序。好比:如今咱们上课一边使用编辑器,一边使用录屏软件,同时还开着画图板, dos窗口等软件。此时,这些程序是在同时运行,”感受这些软件好像在同一时刻运行着“。
实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对咱们的感受要快,看上去就是在同一时刻运行。
其实,多线程程序并不能提升程序的运行速度,但可以提升程序运行效率,让CPU的使用率更高。java
代码示例:浏览器
public class Demo { public static void main(String[] args) { fun(); System.out.println(Math.abs(-9)); } public static void fun() { for(int i=0;i<10000; i++) { System.out.println(i); } } }
当在某个线程中运行的代码建立一个新的Thread对象时,新线程的优先级最初设置为等于建立线程的优先级,而且当且仅当建立线程是守护进程时才是守护进程线程。安全
经常使用构造方法多线程
Thread() Allocates a new Thread object. Thread(Runnable target) Allocates a new Thread object. Thread(Runnable target, String name) Allocates a new Thread object. Thread(String name) Allocates a new Thread object.
经常使用方法并发
一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。建立对象,开启线程。run方法至关于其余线程的main方法。异步
``` class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
```jvm
另外一种方法是声明一个实现 Runnable 接口的类。该类而后实现 run 方法。而后建立Runnable的子类对象,传入到某个线程的构造方法中,开启线程。编辑器
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
代码示例:ide
public class SubThread extends Thread { @Override public void run() { for(int i=0; i<50; i++) { System.out.println("run方法中的变量:"+i); } } } public class ThreadDemo { public static void main(String[] args) { // 一、JVM从入口main开始执行主线程,从CPU开启第一条线程路径,执行main()方法。 SubThread subThread = new SubThread(); // 二、建立线程对象,至关于开启了一个新的线程,从CPU开启第二条线程路径,执行run()方法。 subThread.start(); // 三、执行start方法时,调用run()方法,与main()方法同时要调用CPU,两个执行路径都会被CPU执行,CPU本身选择的权利,出现执行结果,随机性结果。 for(int i=0; i<50; i++) { System.out.println("main方法中的变量:"+i); } } }
Thread t1 = new Thread();t1.start();
Java API 中函数
String getName() // 返回线程的名字 static Thread currentThread() // 获取当前线程
示例:
public class NameThread extends Thread { @Override public void run() { System.out.println(super.getName()); // 输出本线程的名字 } } /* * 每一个线程都有本身的名字 * 运行方法main线程的名字是"main" * 其余线程也有名字,默认为"Thread-0","Thread-1", ... * 得到主线程的名字的方法:JVM开启主线程,运行方法main,主线程也是线程,是线程必然是Thread类的对象,Thread类中的静态方法: * static Thread currentThread() 返回正在执行的线程对象 * 该对象调用getName方法,获取线程名字 */ public class ThreadDemo2 { public static void main(String[] args) { NameThread nameThread = new NameThread(); nameThread.start(); // 获取主线程的线程名 System.out.println(Thread.currentThread().getName()); } }
Java API 中
Thread(String name) // 分配一个新的名字为name的对象 void setName(String name) // 改变线程的名字为name
方法一:
// 在主线程中 NameThread nameThread = new NameThread(); nameThread.setName("Thread线程名字");
方法二:
// 在建立的线程类中的run方法中,调用Thread父类构造函数 super("Thread线程名字");
代码:
public class SleepThread extends Thread{ @Override public void run() { for(int i=0; i<5; i++) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } } } public class ThreadDemo { public static void main(String[] args) throws InterruptedException { SleepThread sleepThread = new SleepThread(); sleepThread.start(); Thread.sleep(2000); } }
建立线程的另外一种方法是声明实现 Runnable 接口的类。该类而后实现 run 方法。而后建立Runnable的子类对象,传入到某个线程的构造方法中,开启线程。
为什么要实现Runnable接口,Runable是啥玩意呢?继续API搜索。
查看Runnable接口说明文档:Runnable接口用来指定每一个线程要执行的任务。包含了一个 run 的无参数抽象方法,须要由接口实现类重写该方法。
Java API 中
// Runnable接口中只有一个run方法 // 方法摘要 void run() // 当使用实现接口Runnable的对象来建立线程时,启动该线程会致使在该单独执行的线程中调用该对象的run方法。 // 建立线程使用Thread类中的构造方法: Thread(Runnable target) // 分配一个线程对象,参数为Runnable接口实现类的对象
示例:
public class SubRunnable implements Runnable{ @Override public void run() { for(int i=0; i<50; i++) { System.out.println("run..."+i); } } } /** * 实现接口方式的线程 * 建立Thread类对象,构造方法中,传递Runnable接口实现类对象 * 调用Thread类的方法start */ public class RunnableDemo { public static void main(String[] args) { SubRunnable subRunnable = new SubRunnable(); Thread t = new Thread(subRunnable); t.start(); for(int i=0; i<50; i++) { System.out.println("main..."+i); } } }
线程状态图:
线程池示意图:
- 在java中,若是每一个请求到达就建立一个新线程,开销是至关大的。在实际使用中,建立和销毁线程花费的时间和消耗的系统资源都至关大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了建立和销毁线程的开销以外,活动的线程也须要消耗系统资源。若是在一个JVM里建立太多的线程,可能会使系统因为过分消耗内存或“切换过分”而致使系统资源不足。为了防止资源不足,须要采起一些
办法来限制任何给定时刻处理的请求数目,尽量减小建立和销毁线程的次数,特别是一些资源耗费比较大的线程的建立和销毁,尽可能利用已有对象来进行服务。
- 线程池主要用来解决线程生命周期开销问题和资源不足问题。经过对多个任务重复使用线程,线程建立的开销就被分摊到了多个任务上了,并且因为在请求到达时线程已经存在,因此消除了线程建立所带来的延迟。这样,就能够当即为请求服务,使用应用程序响应更快。另外,经过适当的调整线程中的线程数目能够防止出现资源不足的状况。
本身建立线程池(伪代码示例)
ArrayList<Thread> threads = new ArrayList<Thread>(); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); // 程序一开始的时候,建立多个线程对象,存储到集合中,须要线程,从集合中获取线程出来 Thread t = threads.remove(0); // 使用线程 t.start(); // 线程用完,回到容器中继续等待使用 threads.add(t);
从JDK5开始,内置线程池技术,不须要本身建立,直接使用便可。
示例:
public class ThreadPoolRunnable implements Runnable{ @Override public void run() { System.out.println(new Thread().getName()); } } import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /* * JDK1.5以后的新特性,实现线程池程序 * 一、使用工厂类,Executors中的静态方法建立线程对象,指定线程个数 * 二、static ExecutorsService newFixedThreadPool(int 线程个数) 返回线程池对象 * 三、返回的是 ExecutorsService接口的实现类(线程池对象) * 四、接口实现类对象,调用方法submit(Runnable r) 提交线程,执行任务 */ public class ThreadPoolDemo { public static void main(String[] args) { // 调用工厂类的静态方法,建立线程池对象 // Executors.newFixedThreadPool(2);返回线程池对象,是接口的实现类对象 ExecutorService es = Executors.newFixedThreadPool(2); // 调用接口实现类对象es的方法submit,提交一个线程任务 es.submit(new ThreadPoolRunnable()); es.submit(new ThreadPoolRunnable()); es.submit(new ThreadPoolRunnable()); } }
<T> Future<T> submit(Callable<T> task)
:获取线程池中的某一个线程对象,并执行线程中的call()方法示例:
import java.util.concurrent.Callable; public class ThreadPoolCallable implements Callable<String>{ @Override public String call() throws Exception { return "abc"; } } import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(2); // 提交任务的方法,返回Future接口的实现类 Future<String> f = es.submit(new ThreadPoolCallable()); String s = f.get(); System.out.println(s); } }
``` import java.util.concurrent.Callable; /* * 多线程的异步计算 * */ public class GetSumCallable implements Callable<Integer>{ private int a; public GetSumCallable(int a) { this.a = a; } @Override public Integer call() throws Exception { int sum = 0; for(int i=0; i<=a; i++) { sum += i; } return sum; } } import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(2); Future<Integer> f1 = es.submit(new GetSumCallable(100)); // 加法 Future<Integer> f2 = es.submit(new GetSumCallable(200)); // 减法 System.out.println("1+2+...+100 = "+f1.get()); System.out.println("1+2+...+200 = "+f2.get()); es.shutdown(); } } ```