多线程相关概念
1、线程三组概念
(1)程序与进程
程序:一组运行逻辑和数据的集合,是一个静态概念,一般存储在磁盘中。
进程:一个正在运行的程序,程序一次运行,是一个动态概念,一般加载在内存中。
(2)进程与线程
进程:正在运行的程序,该程序独立占用资源,是资源分配的一个单位。
线程:独立运行任务的路径。多线程:程序运行过程中,需要多个子任务协同执行,每个线程完成一个任务,任务之间不会相互依赖,独立执行。
进程和线程关系:一个进程最少由1个线程组成,一个进程中多个线程共享进程分配的资源。

(3)并行与并发
并行:多个线程同时执行,需要多核CPU,多个线程同时获取CPU资源,共同执行。
并发:多个线程同时发起,如单核CPU,在同一个CPU时间片中,只能有一个线程获取到CPU资源,其他线程只能等待获取。在多任务系统中,由于CPU分配给线程时间偏非常短,且CPU运行效率非常高,用户感觉是多个任务同时执行。

多线程的实现方式
1、继承方式实现
class MyThread extends Thread {
@Override
public void run() {
Demo1_多线程实现方式.method();
}
}
public class Demo1_多线程实现方式 {
public static void method() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
}
}
public static void main(String[] args) {
//method();
//创建子线程
MyThread th = new MyThread();
//启动子线程
th.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
}
}
//说明:Demo1_多线程实现方式是一个程序,当其运行时就变成了进程。
//该进程为该程序分配了资源(CPU,内存),由于该程序具有两个子任务
//问题:通过执行该程序,发现并没有子线程并发或并行两个子任务。
//分析:该程序还是单线程程序,没有开启多线程服务。
//问题:如何开启多线程服务呢?继承方式/实现方式
}

2、实现方式实现
class MyRunnable implements Runnable{
@Override
public void run() {
Demo1_多线程实现方式.method();
}
}
public class Demo1_多线程实现方式 {
public static void method() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
}
}
public static void main(String[] args) {
//实现方式开启子线程
//创建任务类
MyRunnable ru = new MyRunnable();//任务类
//创建线程类
Thread th = new Thread(ru);
//开启子线程
th.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
}
}
//说明:Demo1_多线程实现方式是一个程序,当其运行时就变成了进程。
//该进程为该程序分配了资源(CPU,内存),由于该程序具有两个子任务
//问题:通过执行该程序,发现并没有子线程并发或并行两个子任务。
//分析:该程序还是单线程程序,没有开启多线程服务。
//问题:如何开启多线程服务呢?继承方式/实现方式
}

3、继承和实现多线程区别
(1)继承方式比实现方式代码更加简洁
(2)继承方式只能单继承名,实现方式是多实现,所以灵活性和可扩展性实现方式更强。
4、其他实现多线程方式
public class Demo2_其他多线程实现方式 {
public static void method() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
}
}
public static void main(String[] args) {
//其他实现方式(继承内部类)
Thread th = new Thread(){
@Override
public void run() {
Demo2_其他多线程实现方式.method();
}
};
th.start();
//(实现内部类)
Thread th2 = new Thread(new Runnable() {
@Override
public void run() {
Demo2_其他多线程实现方式.method();
}
});
th2.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
}
}
}
Thread常用方法
1、获取/设置线程名称


public class Demo3_常用方法 {
public static void main(String[] args) {
//通过getName()获取线程名称
Thread th = new Thread("ConsThread") {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
}
System.out.println("在任务内获取子线程名称:"+this.getName());;
}
};
//setName(String) 设置子线程名称
//th.setName("myThread");
th.start();
//getName() 获取子线程名称
System.out.println("在任务外获取子线程名称:" + th.getName());//Thread-0
//结论:子线程具有默认名称,名称格式:Thread-数字(子线程下标,以0开始算起)
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
}
}
}
2、获取执行任务的线程对象

class Test{
@Override
protected void finalize() throws Throwable {
System.out.println("执行垃圾回收的线程名称:" + Thread.currentThread().getName());//Finalizer
super.finalize();
}
}
public class Demo3_常用方法 {
public static void main(String[] args) {
Test test = new Test();
test = null;
System.gc();
System.out.println("测试垃圾回收线程...");
//method2();
//method1();
}
private static void method2() {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
}
//this.getName();报错
//原因:由于匿名内部类实现Runnable接口,所以该类是一个任务类,任务类没有getName()方法。
System.out.println("任务内获取子线程名称:" + Thread.currentThread().getName());//Thread-0s
}
});
th.start();
System.out.println("任务外获取子线程名称:" + th.getName());//Thread-0
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
}
//面试题1:main方法被哪个线程执行呢?
System.out.println("获取执行mian方法的线程名称:" + Thread.currentThread().getName());//main
//面试题2:对象垃圾回收机制,回收垃圾对象的线程是什么线程?
}
}
3、线程休眠

public class Demo3_常用方法 {
public static void main(String[] args) {
//休眠方法
Thread th = new Thread() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
try {
//.sleep(long) 使执行该方法的线程进入多少毫秒休眠状态
//注意1:使用该方法时必须进行异常处理。
//注意2:被休眠线程,会释放占用资源,但还保留争取资源的权利
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
th.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
}
}
}
4、守护线程

public class Demo3_常用方法 {
public static void main(String[] args) {
//守护线程:子线程保存父线程,如果父线程中断,该子线程也会同时中断。这子线程就是守护线程。
Thread th = new Thread() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//setDaemon(boolean),参数为true,则该线程被设置守护线程。
th.setDaemon(true);
//isDaemon() 判断是否是守护线程,如果是返回true,否则返回false
System.out.println("子线程是否是守护线程:" + th.isDaemon());//false
//应用:软件后台更新线程,是守护线程。
th.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i + "%%%");
int i1 = i / 0;//程序中断
//注意:异常出现后,只会影响该异常出现的线程中断,其他子线程不会收到影响。
}
}
}
线程同步问题
1、同步代码块
概念:
多线程的程序,线程1未完成自己的任务便释放了资源,线程2后去该资源后执行其任务,导致结果出现错误,该错误就是由于线程安全问题。
2、同步代码块
synchronized (锁对象) {
需要同步的代码
}
synchronized 是关键字,表示同步
锁对象:用于管理线程,线程获取锁对象后才能进入同步代码块,否则已在外等候,直到其他线程释放锁对象,它获取才能进入。
import java.io.InputStream;
public class Demo4_线程同步问题 {
public static void main(String[] args) {
//锁对象:可以是任意对象
Object obj = new Object();
//InputStream obj = System.in;
Thread th = new Thread(){
@Override
public void run() {
while(true){
synchronized (obj) {
System.out.println("中");
System.out.println("公");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("教");
System.out.println("育");
}
}
}
};
Thread th2 = new Thread(){
@Override
public void run() {
while(true){
synchronized (obj) {
System.out.println("优");
System.out.println("就");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业");
}
}
}
};
th.start();
th2.start();
//线程同步问题的注意点
//1、多线程的程序,才会出现线程安全问题。
//2、线程安全问题体现在:线程1未完成自己的任务便释放了资源,线程2后去该资源后执行其任务,导致结果出现错误,该错误就是由于线程安全导致的。
//如何解决同步问题呢?
//1、同步代码块 2、同步函数
//同步代码块:
//定义位置:定义在函数(方法)中
//语法:
// synchronized (锁对象) {
// 需要同步的代码
// }
//synchronized 是关键字,表示同步
//锁对象:用于管理线程,线程获取锁对象后才能进入同步代码块,否则已在外等候,直到其他线程释放锁对象,它获取才能进入。
}
}
2、同步函数(方法)
访问修饰符 synchronized 返回值类型 方法名(参数列表){
方法体
}
同步方法作用:对方法体内容添加锁,线程进入方法体便获取了锁,离开方法便释放锁。
import java.io.InputStream;
public class Demo4_线程同步问题 {
public synchronized static void method(){
System.out.println("中");
System.out.println("公");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("教");
System.out.println("育");
}
public synchronized static void function(){
System.out.println("优");
System.out.println("就");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业");
}
public static void main(String[] args) {
//锁对象:可以是任意对象
Object obj = new Object();
//InputStream obj = System.in;
Thread th = new Thread(){
@Override
public void run() {
while(true){
Demo4_线程同步问题.method();
}
}
//属于th的同步方法
// public synchronized void method(){
// System.out.println("中");
// System.out.println("公");
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("教");
// System.out.println("育");
// }
};
Thread th2 = new Thread(){
@Override
public void run() {
while(true){
Demo4_线程同步问题.function();
}
}
//属于th2同步方法
// public synchronized void method(){
// System.out.println("优");
// System.out.println("就");
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("业");
// }
};
th.start();
th2.start();
//问题:加了同步方法,未能解决同步问题?
//答案:两个同步方法的锁不一样。
//注意:非静态同步方法的锁 是 对象本身。
// 静态同步方法的锁 是类对象本身。
}
}
3、同步在API中的应用
(1)StringBuilder和StringBuffer
(2)集合工具类中方法使用集合同步

import java.util.*;
public class Demo5_集合中的同步 {
public static void main(String[] args) {
Collection<String> col = new ArrayList();
Collection<String> coll = Collections.synchronizedCollection(col);
List<String> list = new ArrayList();
List<String> list2 = Collections.synchronizedList(list);
Set<String> set = new HashSet<>();
Set<String> set2 = Collections.synchronizedSet(set);
Map<String,String> map = new HashMap<>();
Map<String, String> map2 = Collections.synchronizedMap(map);
}
}
4、线程生命周期
(1)线程生命周期中的状态

(2)线程生命周期中状态的转换


public class Demo6_线程生命周期 {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("子线程线程状态为:" +this.getState());//RUNNABLE
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
System.out.println("子线程线程状态为:" + thread.getState());//NEW
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程线程状态为:" +thread.getState());//TIMED_WAITTING
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程线程状态为:" +thread.getState());//TERMINATED
}
}
线程池技术
1、概念:
用于解决频繁生成和销毁线程问题,在开发中子任务功能简单,但是需要线程来执行,线程执行完毕又要销毁,而该任务需要多个线程并发执行,从而导致频繁生成销毁线程,会大大降低软件运行效率。所以需要使用线程池技术解决。
2、运行原理:
创建线程池时,先初始化多个线程,接收到子任务派遣(无需生成)线程去执行,执行完毕后重新回收(无需销毁)线程。热昂线程等待下一次派遣。
3、代码示例
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable3 implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "..." + i);//pool-1-thread-1
}
}
}
public class Demo7_线程池技术 {
public static void main(String[] args) {
MyRunnable3 mr1 = new MyRunnable3();
MyRunnable3 mr2 = new MyRunnable3();
MyRunnable3 mr3 = new MyRunnable3();
MyRunnable3 mr4 = new MyRunnable3();
/*生成带一个线程的线程池
//.newSingleThreadExecutor() 生成带一个线程的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
//.submit(Runnable) 接收并派遣线程执行该任务
executorService.submit(mr);
//.shutdown() 释放线程池资源
executorService.shutdown();*/
//自定义多个线程的线程池
//.newFixedThreadPool(3) 自定义带3个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(mr1);
executorService.submit(mr2);
executorService.submit(mr3);
executorService.submit(mr4);
executorService.shutdown();
}
}
本文围绕Java多线程展开,介绍了线程相关概念,如程序与进程、进程与线程、并行与并发。阐述了多线程的实现方式,包括继承和实现方式及其区别。还讲解了Thread常用方法、线程同步问题及解决办法,最后介绍了线程池技术,以解决频繁生成和销毁线程的效率问题。
1740

被折叠的 条评论
为什么被折叠?



