1、什么是进程
进程是操作系统中的一个任务(一个应用程序运行在进程中)
进程是包含某些资源的内存区域
当操作系统创建一个进程后,该进程会自动申请一个名主线程的线程
2、什么是线程
进程中包含一个或者多个的单元称为线程
线程只属于一个进程,并且它只能访问该线程所拥有的资源
一个进程可能包含多个线程
3、进程和线程的区别
一个进程可以包含多个线程
线程的划分尺度小于进程,使得多线程程序的并发性提高
进程在执行过程中拥有独立的内存单元,而多个线程共享该内存单元,从而极大的提高了程序的运行效率
线程不能独立执行
4、并发原理
多个线程“同时”运行只是我们感官上的一种表现
事实上线程是并发运行的,当获得了时间片段的线程被CPU与运行,而其他线程全部等待,微观上说是“走走停停“,宏观上说是都在“运行”,但绝对不是绝对意义上的同时发生(该描述描述单CPU,单线程的电脑)
5、创建线程的2种方式
第一种方式
package com.topxin.thread;
public class ThreadDemo1 {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
/**
* 启动线程调用线程的start(),而不是run()方法
* run()方法是线程定义的任务
* 此时调用start()方法,线程状态改变为就绪状态,等待cpu分配时间片段
* 当获取了时间片段之后,则执行线程run()方法,此时状态为运行状态
*/
t1.start();
t2.start();
}
}
/**
* 第一创建线程的方式有俩个不足
* 1、由于java是单一继承的,所以导致当前类继承Thread之后,不能继承其他类。
* 2、由于线程内部重写了run()方法的线程任务,这就导致该线程与执行的任务有一耦合关系,不利于线程服用
*/
class MyThread1 extends Thread{
@Override
public void run() {
for(int i=0;i<1000;i++) {
System.out.println("你是谁啊???");
}
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for(int i=0;i<1000;i++) {
System.out.println("我是隔壁老王啊!!!");
}
}
}
第二种方式
package com.topxin.thread;
public class ThreadDemo2 {
public static void main(String[] args) {
Runnable r1=new MyRunnable1();
Runnable r2=new MyRunnable2();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
/**
* 第二种创建线程方式
* 1、接口可以多实现,这样改类就可以继承其他类,可以更好的扩展该类
* 2、将线程的任务与线程分离,达到一个低耦合的关系,达到线程复用
*/
class MyRunnable1 implements Runnable{
@Override
public void run() {
for(int i=0;i<1000;i++){
System.out.println("你瞅啥...");
}
}
}
class MyRunnable2 implements Runnable{
@Override
public void run() {
for(int i=0;i<1000;i++){
System.out.println("瞅你咋的...");
}
}
}
匿名内部类创建
package com.topxin.thread;
/**
* 通过匿名内部类创建
*/
public class ThreadDemo3 {
public static void main(String[] args) {
Thread t1 = new Thread() {
@Override
public void run() {
for(int i=0;i<1000;i++){
System.out.println("你是谁呀....");
}
}
};
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<1000;i++){
System.out.println("我是你王哥呀...");
}
}
});
t1.start();
t2.start();
}
}
6、start()和run()方法的区别
启动线程是调用start()方法,而不是直接调用run()方法
start()方法会将线程纳入线程调度,使得当前线程可以运行,当线程获取时间片段之后会自动执行run()方法逻辑
7、操作线程API
currentThread()方法,可以获取运行当前代码片段的线程
package com.topxin.thread;
public class ThreadDemo4 {
public static void main(String[] args) {
//获取运行main方法的线程
Thread main = Thread.currentThread();
System.out.println(main);
doSome();
Thread t = new Thread() {
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println("自定义线程"+t);
doSome();
}
};
t.start();
}
protected static void doSome() {
Thread t = Thread.currentThread();
System.out.println("运行doSome方法的当前线程"+t);
}
}
运行结果
Thread[main,5,main]
运行doSome方法的当前线程Thread[main,5,main]
自定义线程Thread[Thread-0,5,main]
运行doSome方法的当前线程Thread[Thread-0,5,main]
线程的一些其他方法
package com.topxin.thread;
public class ThreadDemo5 {
public static void main(String[] args) {
Thread main = Thread.currentThread();
//获取当前线程的标识符
long id = main.getId();
System.out.println(id); //1
//获取线程的名称
String name = main.getName();
System.out.println(name); //main
//设置线程名称
main.setName("Thread-main");
System.out.println(main.getName()); //Thread-main
//判断线程是否活动状态
boolean alive = main.isAlive();
System.out.println(alive); //true
//判断线程是否是守护线程
boolean daemon = main.isDaemon();
System.out.println(daemon); //false
//判断线程是否中断
boolean f = main.isInterrupted();
System.out.println(f); //false
}
}
sleep()方法使用场景演示
package com.topxin.thread;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 使用sleep()方法实现电子表功能
* 输出格式为 HH:mm:ss
*/
public class ThreadDemo6 {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
while(true) {
Date date = new Date();
try {
Thread.sleep(1000);
System.out.println(sdf.format(date));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
8、守护线程
守护线程,又称为后台线程
当一个进程中的所有前台线程结束,进程结束,此时无论进程中是否有后台线程,都会被强制结束。
默认创建出来的线程都是前台线程,后台线程需要单独设置
serDaemon(true)默认为false
package com.topxin.thread;
/**
* 演示守护线程(后台线程)
*/
public class ThreadDemo7 {
public static void main(String[] args) {
Thread rose = new Thread() {
@Override
public void run() {
for(int i = 0;i < 5;i++) {
System.out.println("rose: let me go!!!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("rose:啊啊啊啊啊");
System.out.println("音效:噗通,daung");
}
};
Thread jack = new Thread() {
@Override
public void run() {
while(true) {
System.out.println("jack:you jump I jump");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//设置jack为守护线程,在启动之前设置
jack.setDaemon(true);
rose.start();
jack.start();
}
}
9、Thread类提供的静态方法yield()
yield()该方法用于使当前线程主动让出CPU时间片段
回到就绪Runnable状态,等待重写分配时间片段
package com.topxin.thread;
public class ThreadDemo8 {
public static void main(String[] args) {
final Card c = new Card();
Thread t1 = new Thread() {
@Override
public void run() {
while(true) {
int b = c.getMoney();
Thread.yield();//模拟线程切换
System.out.println("t1:"+b);
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
while(true) {
int b = c.getMoney();
Thread.yield();//模拟线程切换
System.out.println("t2:"+b);
}
}
};
t1.start();
t2.start();
}
}
class Card{
private int money = 20;
public int getMoney() { //模拟取钱
if(money == 0) {
throw new RuntimeException("没有钱了。。。"); //如果没钱主动抛出异常
}
Thread.yield(); //模拟线程切换
return money--;
}
}
正常情况2个线程同时取钱,等money=0会抛出异常
但是也会出现如下情况,程序没有抛出异常结束,无线循环下去
10、join()方法(Waits for this thread to die.)
join方法会将调用的线程至于阻塞状态,只带等待的线程执行完毕之后才会解除阻塞自动运行
package com.topxin.thread;
/**
* 演示join方法实现线程同步
*/
public class ThreadDemo8 {
public static void main(String[] args) {
Thread dowload = new Thread() {
@Override
public void run() {
for(int i=1;i<=100;i++){
System.out.println("dow:开始下载"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("dow:下载完毕。。。");
}
};
Thread show = new Thread(){
@Override
public void run() {
//等待dowload线程执行结束之后,才解除阻塞
try {
dowload.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("show:开始显示图片");
for(int i=1;i<=100;i++){
System.out.println("show:显示"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("显示图片完毕...");
}
};
dowload.start();
show.start();
}
}
11、同步操作
有先后顺序的操作,性能稍慢,相当于你干完,我在干
12、异步操作
多线程并发操作,性能稍快,相当于大家一起干,各干各的
13、线程同步
多个线程并发读取同一个资源,会发生线程安全问题
常见问题如:1)多线程共享实例变量 2)多线程共享静态的公共资源
解决线程安全问题:将多线程异步操作变成同步操作