网站首页 > 精选教程 正文
一 多线程入门
1.1 线程和进程
进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。
单位 : 天 年 厘米 克 MB 事务
1.2 多线程
我们程序运行的时候 肯定至少有一个执行单元 就是一个线程 并且我们称之为 main 主线程。
如果我们希望在开辟其他的线程去执行代码 ,其他的线程就称之为 分线程。
主线程和分线程一起执行的时候 就有多个执行单元,我们统称为 多线程。
1.3 多线程的目的
煮一个鸡蛋需要三分钟,煮三个鸡蛋需要几分钟?
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。
1.4 java开启多线程的几种方式
多线程是在主线程中 开启了一个分线程所以产生了多线程。
单线程
public static void main(String[] args) {
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
for (int i=0;i<9999;i++){
System.out.println("B"+i);
}
}
A 继承Thread类方式
创建一个 继承 Thread 重写run函数
public class Haha extends Thread {
@Override
public void run() {
for (int i=0;i<9999;i++){
System.out.println("B"+i);
}
}
}
创建该类对象 调用start方法
public static void main(String[] args) {
Haha haha = new Haha();
haha.start();
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
方式二 实现Runnable接口
创建一个类 实现Runnable接口 重写run函数
public class Hehe implements Runnable {
@Override
public void run() {
for (int i=0;i<9999;i++){
System.out.println("B"+i);
}
}
}
开启分线程 创建该类对象 创建Thread对象并且将该类对象构造函数传参 再使用Thread对象调用start函数
public static void main(String[] args) {
Hehe hehe = new Hehe();
Thread thread = new Thread(hehe);
thread.start();
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
方式三 匿名内部类的形式
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, target, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* @param target
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this classes {@code run} method does
* nothing.
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
第二种方式开启分线程的时候 Thread参数类型为 Runnable接口对象形式。我们完全可以使用匿名内部类创建该类对象
public static void main(String[] args) {
// 匿名 People p = new People() new Runnable ()
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
Thread thread = new Thread(runnable);
thread.start();
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
});
thread.start();
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<9999;i++){
System.out.println("B"+i);
}
}
}).start();
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
方式4 实现Callable形式
public static void main(String[] args) {
FutureTask task = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
for (int i = 0; i < 1000; i++) {
System.out.println("第1个for循环"+i);
}
return null;
}
});
new Thread(task).start();
for (int i = 0; i < 1000; i++) {
System.out.println("第2个for循环"+i);
}
}
(1)Callable规定的方法是call(),而Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call()方法可抛出异常,而run()方法是不能抛出异常的。
(4)运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。
它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
1.5 线程函数基本函数
public static void main(String[] args) {
System.out.println("你好 世界");
new Thread(new Runnable() {
@Override
public void run() {
long id = Thread.currentThread().getId(); //当前线程的id
String name = Thread.currentThread().getName();//当前线程的名字
System.out.println(id+"-----"+name);
}
} , "hahahaha" ).start();
try {
Thread.sleep(1000); // 线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread.sleep(1000); // 线程休眠
long id = Thread.currentThread().getId(); //当前线程的id
String name = Thread.currentThread().getName();//当前线程的名字
1.6 线程函之守护线程
什么是守护线程?
所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因 此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
守护线程和用户线程的没啥本质的区别:唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。
垃圾回收线程
垃圾: 不再被使用的内存
垃圾回收:清除不被使用的对象 让其锁占据的内存可以被重新分配
垃圾回收的方式: 手动回收 (c语言 xxx .... xxx.free()) 自动回收 (java GC机制 创建一个守护线程 定期清理内存)
垃圾回收算法: gc线程如何判断某个对象是不是垃圾
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
});
/*设置当前线程为守护线程*/
thread.setDaemon(true);
thread.start();
for (int i=0;i<10;i++){
System.out.println("B"+i);
}
}
1.7 线程的优先级
在操作系统中,线程可以划分优先级,优先级高的线程得到的CPU资源较多,也是CPU优先执行优先级较高的线程对象中的任务。
设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。
设置优先级使用setPriority()[pra????r?ti] 方法。 1-10参数
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<9999;i++){
System.out.println("A"+i);
}
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<9999;i++){
System.out.println("B"+i);
}
}
});
thread.setPriority(1);
thread1.setPriority(10);
thread.start();
thread1.start();
}
1.8 多线程中的概念
AJAX的异步。js是单线程 如何实现的异步?
1.9 四种线程池
面试题 : 线程池的应用场景
除了我们 继承Thread类 实现 Runnable接口 实现Callable接口 匿名内部类的形式创建线程之外
还可以使用线程池创建线程。
A 缓存线程池
public static void main(String[] args) {
//创建一个缓存线程池 相当于创建了一个池子
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i <10; i++) {
final int index = i;
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"---------"+index);
}
});
}
}
体现出一个复用的思想
特点
会根据需要创建新线程,如果线程池中有可复用的,会先复用可用的。
这个线程池典型的场景是改善 任务耗时短小的 异步任务。
使用execute可以复用可用的线程。如果没有可用线程,会创建新线程并添加到线程池里。
那些1分钟没有被使用的线程将被停止并从缓存里移除。
B 定容线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i <10; i++) {
final int index = i;
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"---------"+index);
}
});
}
特点
可以复用指定数目的线程
如果请求的线程数目大于目前定容的数量,那么多余的请求将被等待,直到线程池中有可用的线程。
如果有任何线程执行过程中停止了,将会新建一个线程代替。
线程池中的线程一直存活,直到显式的使用shutdown关闭。
C 定时线程池
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
for (int i = 0; i <10; i++) {
final int index = i;
pool.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"---------"+index);
}
},5, TimeUnit.DAYS);
}
}
特点:支持定时及循环任务执行。延迟定时,延迟的时间间隔是从调用开始开始计算的,并不受线程执行时间长短的影响。
D 单一线程池
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i <10; i++) {
final int index = i;
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"---------"+index);
}
});
}
}
特别: corePoolSize = 1 maxPoolSize = 1; 最多只开启一个线程,对于队列中的Runnable,挨个执行。
猜你喜欢
- 2024-11-23 线程生命周期
- 2024-11-23 线程同步synchronized(不同步的问题、队列与锁),死锁产生和解决
- 2024-11-23 面试突击31:什么是守护线程?它和用户线程有什么区别?
- 2024-11-23 Java之TimeUnit的使用
- 2024-11-23 每日分享- NodeJS 程序中实现线程睡眠
- 2024-11-23 Java 17 多线程中的守护线程
- 2024-11-23 美团面试真题之一个线程OOM,进程里的其他线程还能运行吗?
- 2024-11-23 Java多线程-线程中断interrupt
- 2024-11-23 C++ 让线程休眠特定时间
- 2024-11-23 什么是线程死锁?形成条件是什么?如何避免?
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)