深圳有做网站的公司660元,全球搜官网,多种语言网站怎么做,营销型外贸网站建设公司#xff08;一#xff09;线程基本概念 一、 程序, 进程, 线程的概念 程序: 使用某种语言编写一组指令(代码)的集合,静态的
进程: 运行的程序,表示程序一次完整的执行, 当程序运行完成, 进程也就结束了
个人电脑: CPU 单个, 双核, CPU的时间分片, 抢占式
每个独立执行的程…一线程基本概念 一、 程序, 进程, 线程的概念 程序: 使用某种语言编写一组指令(代码)的集合,静态的
进程: 运行的程序,表示程序一次完整的执行, 当程序运行完成, 进程也就结束了
个人电脑: CPU 单个, 双核, CPU的时间分片, 抢占式
每个独立执行的程序称为进程
每个进程都有自己独立的内存空间, 进制之间的通信很困难
在操作系统中进程是进行系统资源分配、调度和管理的最小单位进程在执行过程中拥有独立的内存单元。比如Windows采用进程作为最小隔离单位每个进程都有自己的数据段、代码段并且与别的进程没有任何关系。因此进程间进行信息交互比较麻烦
线程: 一个进程中,可以同时有多条执行链路, 这些执行链路称为线程, 线程是CPU的调度与分配最小单位, 同一个进程多个线程共享这个进程的内存资源: JVM内存模型 二、进程与线程区别: 进程包含线程, 一个进程包含多个线程, 一个进程最小必须包含一个线程(主线程,main线程), 运行main()方法的时候, 创建了一个main线程 一个进程死亡了, 这个进程中所有的线程死亡 线程销毁进程未必会关闭 并行: 多CPU执行各种不同任务, 并发: 一个CPU执行不同的任务(多个线程) 多线程速度快吗? 看CPU的核数,个数 三、多线程 多线程是指一个进程在执行过程中可以产生多个线程这些线程可以同时存在、同时运行形成多条执行线 二java实现多线程
在jdk.1.5之前: 创建线程的方式: 两种:
继承Thread类实现Runnable接口
在JDK1.5之后: 多加了两种:
实现 Callable接口线程池
第一种方式: 继承Thread 编写一个类继承Thread,该类是线程类 重写run(), 编写该线程需要完成的任务 创建线程类对象 调用start()方法,启动线程 /*** 实现线程的第一种方式:* 继承Thread*/
public class MyThread1 extends Thread{
//private static Object o new Object();public MyThread1(String name) {super(name);}
//重写run()方法Overridepublic void run() {//线程完成的功能for (int i 1; i 10 ; i) {//得到当前正在运行的线程//Thread.currentThread()//getName() 得到线程的名字System.out.println(Thread.currentThread().getName():输出i);}}
} 注意事项: 线程启动,一定是调用start() , 不是调用run(), 如果直接调用run() ,只是方法的调用,没有创建线程一个线程一旦启动,就不能重复启动 第二种方式: 实现Runnable接口 启动线程: 都必须借助Thread的start() Runnable实现类: 就是一个线程的任务类 继承Thread与Runnable接口的区别: 继承Thread类, 这个线程类就不能再继承其他类, 实现Runnable接口, 可以再继承其他类实现Runnable接口, 可以让多个线程共享这个Runnable的实现类对象继承Thread类,启动简单, 实现Runnable接口, 必须依赖Thread类的start()方法 推荐 实现Runnable接口 /*** 线程的第二种实现方式: 实现Runnable接口*/
public class MyRunnable implements Runnable {Overridepublic void run(){//线程需要完成的任务for (int i 1; i 10 ; i) {System.out.println(Thread.currentThread().getName():输出i);}}
}
实际开发中使用
new Thread(new Runnable() {Overridepublic void run() { }}).start(); 第三种方式: 实现Callable接口 第一步编写一个类实现Callable接口,重写call()方法启动线程创建Callable接口实现类对象创建一个FutureTask对象, 传递Callable接口实现类对象, FutureTask异步得到Callable执行结果, 提供get() FutureTask 实现Future接口( get()) 实现Runnable接口创建一个Thread对象, 把FutureTask对象传递给Thread, 调用start()启动线程 /*** 线程的第三种实现方式:* 实现Callable接口*/
public class MyCallable implements CallableString {Overridepublic String call() throws Exception {//线程睡眠 单位: 毫秒Thread.sleep(10000); System.out.println(Thread.currentThread().getName()执行完成);return callable;}
} 第四种方式: 使用线程池创建 1.FixedThreadPool固定大小的线程池。 2.CachedThreadPool缓存线程池。该线程池创建的线程数量不固定当有新任务需要执行时会创建新的线程来执行任务如果有线程处于空闲状态会优先使用空闲线程。适用于执行时间短的任务如处理HTTP请求等。 3.SingleThreadExecutor单线程线程池。该线程池只创建一个线程来执行任务 4.ScheduledThreadPool定时任务线程池。该线程池可以定时执行任务可以设置任务执行的时间、执行周期等。适用于需要定时执行任务的场景如定时备份数据等。 1、使用newCachedThreadPool
newCachedThreadPool创建一个可缓存线程池如果线程池长度超过处理需要可灵活回收空闲线程若无可回收则新建线程。
这种类型的线程池特点是 工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。 如果长时间没有往线程池中提交任务即如果工作线程空闲了指定的时间(默认为1分钟)则该工作线程将自动终止。终止后如果你又提交了新的任务则线程池重新创建一个工作线程。 在使用CachedThreadPool时一定要注意控制任务的数量否则由于大量线程同时运行很有会造成系统瘫痪。
示例代码如下
package test;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService cachedThreadPool Executors.newCachedThreadPool();for (int i 0; i 10; i) {final int index i;try {Thread.sleep(index * 1000);} catch (InterruptedException e) {e.printStackTrace();}cachedThreadPool.execute(new Runnable() {public void run() {System.out.println(index);}});}}} 2、使用newFixedThreadPool
创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程如果工作线程数量达到线程池初始的最大数则将提交的任务存入到池队列中。
FixedThreadPool是一个典型且优秀的线程池它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是在线程池空闲时即线程池中没有可运行任务时它不会释放工作线程还会占用一定的系统资源。
示例代码如下
package test;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService cachedThreadPool Executors.newCachedThreadPool();for (int i 0; i 10; i) {final int index i;try {Thread.sleep(index * 1000);} catch (InterruptedException e) {e.printStackTrace();}cachedThreadPool.execute(new Runnable() {public void run() {System.out.println(index);}});}}}
3、使用newSingleThreadExecutor
创建一个单线程化的Executor即只创建唯一的工作者线程来执行任务它只会用唯一的工作线程来执行任务保证所有任务按照指定顺序(FIFO, LIFO,优先级)执行。如果这个线程异常结束会有另一个取代它保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务并且在任意给定的时间不会有多个线程是活动的。
示例代码如下
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService singleThreadExecutor Executors.newSingleThreadExecutor();for (int i 0; i 10; i) {final int index i;singleThreadExecutor.execute(new Runnable() {public void run() {try {System.out.println(index);Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}});}}
}
4、使用newScheduledThreadPool
创建一个定长的线程池而且支持定时的以及周期性的任务执行支持定时及周期性任务执行。
延迟3秒执行延迟执行示例代码如下
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {public static void main(String[] args) {ScheduledExecutorService scheduledThreadPool Executors.newScheduledThreadPool(5);scheduledThreadPool.schedule(new Runnable() {public void run() {System.out.println(delay 3 seconds);}}, 3, TimeUnit.SECONDS);}
}
表示延迟1秒后每3秒执行一次定期执行示例代码如下
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {public static void main(String[] args) {ScheduledExecutorService scheduledThreadPool Executors.newScheduledThreadPool(5);scheduledThreadPool.scheduleAtFixedRate(new Runnable() {public void run() {System.out.println(delay 1 seconds, and excute every 3 seconds);}}, 1, 3, TimeUnit.SECONDS);}
}
三使用多线程
一、启动线程
1.实现线程的第一种方式:*继承Thread
抢占式执行谁抢到就是谁的main函数最先执行多数情况下
//启动线程//创建线程对象MyThread1 t1 new MyThread1(t1);MyThread1 t2 new MyThread1(t2);MyThread1 t3 new MyThread1(t3);//调用start()启动线程, 线程与其他线程抢占cpu资源, 谁抢到,执行谁的run()中的代码t1.start();t1.start();t2.start();t3.start();
System.out.println(main线程执行完成...);
2.线程的第二种实现方式: 实现Runnable接口
public static void main(String[] args) {
//创建任务对象
MyRunnable task new MyRunnable();
//创建线程: Thread
Thread t1 new Thread(task, t1);
Thread t2 new Thread(task, t2);
//启动线程
t1.start();
t2.start();
}
3.线程的第三种实现方式:实现Callable接口
get(); //阻塞的 main最后执行
MyCallable callable new MyCallable();//再次封装 FutureTaskFutureTaskString task new FutureTask(callable);Thread t1 new Thread(task, t1);//启动线程t1.start();//获取结果// String rs task.get(); //阻塞的, 是main线程在执行//设置一个超时时间, 一旦到达超时时间, 停止执行,抛一个异常//String rs task.get(1, TimeUnit.SECONDS);//取消执行task.cancel(true);//System.out.println(rs);System.out.println(main线程执行完成!!);
二,线程的生命周期
新生状态调用start()方法之前都处于出生状态
就绪状态调用start()方法后处于就绪状态又称为可执行状态
运行状态得到系统资源后处于运行状态
阻塞状态如果一个线程在运行状态下发出输入/输出请求该线程将进入阻塞状态在其等待输入输出结束时线程进入了就绪状态。
线程阻塞:
死亡状态当线程run()方法执行完毕时线程进入死亡状态。 同步阻塞sleep() Thread的方法 时间到自动醒,释放cpu资源,不释放锁, join() 阻塞yield() 礼让, 释放cpu资源, 与其他线程抢CPU资源wait() 等待: Object类中的方法, 一定等待唤醒(notify() notifyAll()), 释放cpu资源,释放锁资源, 线程通信suspend和resume()由jdk1.0提供jdk1.2之后就被放弃了它也是让线程暂停但是它不释放资源,导致死锁出现 t1.yield(); //礼让 Thread.sleep(1000); thread4.join(); //等方法会让线程进入阻塞状态 三,线程同步
同步方法
在方法上添加一个synchronized修饰符, 往对象上加锁
非静态同步方法:锁加在 this(对象)
静态同步方法:锁加在类.class(对象) 锁的释放: 当把同步方法执行完之后,马上释放锁 同步方法: 锁住的代码范围整个方法, 锁的控制粒度太宽 public 返回值类型 方法名(){//...synchronized(锁对象){//锁住的代码}//...
}
四,线程死锁 多个线程,相互之间需要对方的锁, 但是又不释放自己的锁,造成程序卡住, 这些线程都在等待,等待对方的锁, 死锁形成的原因: 互斥锁,排他锁 1 互斥使用即当资源被一个线程使用(占有)时别的线程不能使用 2 不可抢占资源请求者不能强制从资源占有者手中夺取资源资源只能由资源占有者主动释放。 3 请求和保持即当资源请求者在请求其他的资源的同时保持对原有资源的占用。 4 循环等待即存在一个等待队列P1占有P2的资源P2占有P3的资源P3占有P1的资源。这样就形成了一个等待环路 形成死锁的这4个条件缺一不可, 避免死锁: 打破4个条件 的一个就可以 项目一定避免出现死锁: 解决死锁: 使用完某个锁,马上释放 多个线程获取锁的顺序是一致, A线程获取锁: a--b--c B线获取锁: a--b--v 模拟死锁:
A线程 先获取objA锁, 再获取objB锁, 在获取objB锁时,不释放objA锁
B线程 先获取objB锁, 再获取objA锁, 在获取objA锁时,不释放objB锁 四统计线程运行时间
1,java 统计线程运行时间
public class MyThread extends Thread {public void run() {// 线程相关的任务代码for (int i 0; i 1000000; i) {// 模拟线程运行的任务}}public static void main(String[] args) {// 创建线程MyThread thread new MyThread();// 记录开始时间long startTime System.currentTimeMillis();// 执行线程任务thread.start();// 等待线程执行完成thread.join();// 记录结束时间long endTime System.currentTimeMillis();// 输出线程运行时间System.out.println(总耗时::(endTime-startTime)/1000秒);}
}
2,例如:一个任务需要2s执行,现在有十个任务,共需要多久时间?