------- android培训、java培训、期待与您交流! ----------
(一)基本概念
线程:是依赖于进程的执行绪(执行路径/控制单元),是程序使用CPU的基本单位。
进程:当前正在执行的程序,代表一个应用程序在内存中的执行区域。
多进程:同一时间段内执行多个任务。同一时刻只能执行一个任务。如Windows为代表的操作系统。
多进程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。真正的多进程执行是指多核同时计算。
单线程:一个进程中,只有一个线程执行。
多线程:同一个进程中,多个线程执行。这多个线程共享该进程资源(堆内存与方法区),栈内存独立,即每一个线程占用一个栈。
线程两种调度模型:
分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用CPU 的时间片。
抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个。(线程随机性)
Java使用的为抢占调度模型。
线程并行与线程并发
线程并行:正常的多线程执行就是线程并行。即逻辑上同一时间同时运行。
线程并发(异常):由于线程抢占而不应出现的某一时刻的线程及相关数据状态。如并发修改异常的产生。
JVM的启动支持多线程:
JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程”,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。
线程生命周期
(二)线程Thread类常用方法
构造方法:
public Thread()
public Thread(Runnable target)
public Thread(String name)
public Thread(Runnable target,String name)
主要方法:
public final String getName()
public final void setName(String name)
public static Thread currentThread()
public void run()
public void start()
开启一个线程的步骤:
创建一个普通的线程类对象
调用线程的start方法开启线程。此时才真正开始执行一个新的线程。
public void run() 该线程要执行的代码。相当去那个线程的main方法
该方法不是用来调用的,是用来重写的。
public void start() 使该线程开始执行;
Java 虚拟机调用该线程的 run 方法。
自定义线程类继承Thread类。
重写run方法。run方法内为该线程执行代码。将其理解为其他线程的main方法,即该线程的执行入口。
使用:
创建线程对象
开启线程,即调用start方法,该方法会自动调用这个线程的run方法。
自定义Runnable 的子类(非线程类)。
重写run方法。run方法内为该类对象所在线程的执行代码。
同样可将其理解为其他线程的main方法,即该线程的执行入口。
使用:
创建Runnable的子类对象。
使用Runnable的子类对象创建线程对象。
开启线程,即调用start方法,该方法会自动调用这个线程的run方法。
public class Demo01_Thread {
public static void main(String[] args) {
//创建线程对象
MyThread mt = new MyThread();
mt.setName("赵丽颖的线程");
//开启线程,即调用线程的start方法的过程,之后会自动调用run方法
mt.start();
//返回正在执行的线程
Thread currentThread = Thread.currentThread();
//获取线程名称
System.out.println(currentThread.getName());
for (int i = 0; i < 10; i++) {
System.out.println(currentThread.getName()+"今天又敲代码了"+i);
}
}
}
<pre name="code" class="java">public class MyThread extends Thread {
//重写run方法,完成该线程的业务逻辑
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//返回正在执行的线程
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName()+"今天又敲代码了"+i);
}
}
}
方式二代码
<pre name="code" class="java">public class Demo02_Runnable {
public static void main(String[] args) {
//创建线程执行目标类对象
MyRunnable mr = new MyRunnable();
Thread thread = new Thread(mr, "唐嫣");
thread.start();
for (int i = 0; i < 20; i++) {
//获取当前执行的线程
Thread thisThread = Thread.currentThread();
System.out.println(thisThread.getName()+"又敲代码了"+i);
}
}
}
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//获取当前执行的线程
Thread thisThread = Thread.currentThread();
System.out.println(thisThread.getName()+"又敲代码了"+i);
}
}
}
一般普通方法
<pre name="code" class="java">/*
* Thread:线程优先级
* public final void setPriority(int newPriority) 设置调用方法线程的优先级
* public final int getPriority() 返回调用方法线程的优先级
*
* 默认优先级:5
* 最大优先级:10
* 最小优先级:1
*/
public class Demo01_Priority {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.setName("唐嫣");
MyThread mt2 = new MyThread();
mt2.setName("杨幂");
MyThread mt3 = new MyThread();
mt3.setName("屠呦呦");
System.out.println(mt.getPriority());
System.out.println(mt2.getPriority());
System.out.println(mt3.getPriority());
mt.setPriority(10);
mt2.setPriority(1);
mt.start();
mt2.start();
mt3.start();
}
}
/*
* Thread:线程休眠
* public static void sleep(long millis) throws InterruptedException 在指定的毫秒数内让当前正在执行的线程休眠
*
* 该方法为静态方法,不能直接使用线程对象调用。
* 如果想让某个线程休眠,则在该线程的代码中加入该休眠
*/
public class Demo01_Sleep {
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.setName("唐嫣");
MyThread mt2 = new MyThread();
mt2.setName("杨幂");
MyThread mt3 = new MyThread();
mt3.setName("屠呦呦");
mt.start();
mt2.start();
mt3.start();
Thread.sleep(2000);
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"又敲代码了"+i);
}
}
}
<pre name="code" class="java">public class MyThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 20; i++) {
System.out.println(currentThread().getName()+"又敲代码了"+i);
}
}
}
/*
* Thread:加入线程
* public final void join() throws InterruptedException 加入线程,等待该线程终止。
*
* 等待其他线程的线程: join方法代码所在的线程
*
* 被等待执行完毕的线程: 调用join方法的线程
*/
public class Demo01_join {
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.setName("唐嫣");
mt.setPriority(1);
MyThread mt2 = new MyThread();
mt2.setName("杨幂");
mt2.setPriority(10);
mt.start();
mt2.start();
mt.join();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"又敲代码了"+i);
}
}
}
/*
* Thread:线程礼让
*
* public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
*/
public class Demo01_yield {
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.setName("唐嫣");
MyThread mt2 = new MyThread();
mt2.setName("杨幂");
mt.start();
mt2.start();
}
}
<pre name="code" class="java">public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(currentThread().getName()+"又敲代码了"+i);
Thread.yield();
}
}
}
/*
* Thread:守护线程
*
* public final void setDaemon(boolean on) 将线程设置为守护线程
* 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
*/
public class Demo01_daemon {
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.setName("唐嫣");
MyThread mt2 = new MyThread();
mt2.setName("杨幂");
mt.setDaemon(true);
mt2.setDaemon(true);
mt.start();
mt2.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"又敲代码了"+i);
Thread.yield();
}
}
}
<pre name="code" class="java">
/*
* Thread:线程中断
*
* public final void stop() 停止线程,杀死线程
* public void interrupt() 中断线程
*
* 如果该线程处于某种等待状态时,需要中断,则调用该方法。
* 调用方法后,停止等待的线程会抛出一个异常对象,此时只需要捕获该异常,处理异常代码
*/
public class Demo01_interrupt {
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.setName("唐嫣");
MyThread mt2 = new MyThread();
mt2.setName("杨幂");
mt.start();
mt2.start();
Thread.sleep(1000);
// mt.stop();
// mt2.stop();
mt.interrupt();
mt2.interrupt();
}
}
(三)Java同步机制
public class DeadLockThread extends Thread {
boolean flag;//定义标记,用来指定要执行的代码
public DeadLockThread(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag) {//flag赋值为true时,执行的代码
synchronized (Demo01_deadlock.锁1) {
System.out.println("if中锁1");
// try {
// sleep(20);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
synchronized (Demo01_deadlock.锁2) {
System.out.println("if中锁2");
}
}
} else {//flag赋值为false时,执行的代码
synchronized (Demo01_deadlock.锁2) {
System.out.println("else中锁2");
synchronized (Demo01_deadlock.锁1) {
System.out.println("else中锁1");
}
}
}
}
}
public class Demo01_deadlock {
public static Object 锁1 = new Object();
public static Object 锁2 = new Object();
public static void main(String[] args) {
Thread thread = new DeadLockThread(true);
Thread thread2 = new DeadLockThread(false);
thread.start();
thread2.start();
}
}
(四)单例设计模式
(1)保证类在内存中只有一个对象。
(2)怎么保证:
A:构造私有
B:自己造一个对象
C:提供公共访问方式
(3)两种方式:
A:懒汉式
public class Student {
private Student(){}
private static Student s = null;
public synchronized static Student getStudent() {
if(s == null) {
s = new Student();
}
return s;
}
}
B:饿汉式
public class Student {
private Student(){}
private static Student s = new Student();
public static Student getStudent() {
return s;
}
}
(4)JDK的一个类本身也是单例模式的。
Runtime
(五)等待唤醒机制
/*
* 共享数据:一个Person对象
* 生产: 为这个Person对象的属性赋值
* 消费:取这个Person对象的属性值并打印
*
* 当生产者已经生产数据而没有被消费掉时:生产者等待消费者线程消费
* 反之亦然
* Object类的线程等待:
* public final void wait() throws InterruptedException 让其共享数据所在的线程等待
* 该方法会释放掉锁。从哪里等待,唤醒后从哪里继续执行
* sleep方法不会释放锁,因为sleep方法是根据时间判定,是一定会醒的。
*
* Object类的线程唤醒:
* public final void notify() 唤醒已经在共享数据上等待的线程
*/
public class Demo01 {
public static void main(String[] args) {
//创建共享数据
Person p = new Person();
//创建生产者线程执行目标类对象
Runnable scr = new ShenChanRunnable(p);
//创建消费者线程执行目标类对象
Runnable xfr = new XiaoFeiRunnable(p);
//通过线程执行目标类对象创建生产与消费线程对象
Thread shengchan = new Thread(scr);
Thread xiaofei = new Thread(xfr);
//开启线程
xiaofei.start();
shengchan.start();
}
}
public class Person {
private String name;
private int age;
//定义成员变量,记录数据的生产消费状态:true代表有数据 false代表没有数据
boolean flag;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
//定义生产线程线程执行目标类
public class ShenChanRunnable implements Runnable {
//定义Person类型的成员变量,用于接收共享数据
private Person p;
//接收共享数据的构造方法
public ShenChanRunnable(Person p) {
this.p = p;
}
//定义一个标志位,用来标志生产内容
int x = 0;
//重写run方法,完成生产逻辑
@Override
public void run() {
//循环生产
while(true) {
//使用共享数据Person对象p作为锁
synchronized (p) {
//判断是否有数据
if(p.flag) {
//如果有数据,生产者线程就等待
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//为共享数据的属性生产值
if(x%2==0) {
p.setName("汤圆");
p.setAge(800);
}else {
p.setName("唐嫣");
p.setAge(18);
}
x++;
//重置共享数据状态
p.flag = true;
//唤醒其他线程
p.notify();
}
}
}
}
//定义消费线程线程执行目标类
public class XiaoFeiRunnable implements Runnable {
//定义Person类型的成员变量,用于接收共享数据
private Person p;
//接收共享数据的构造方法
public XiaoFeiRunnable(Person p) {
this.p = p;
}
//重写run方法,完成消费逻辑
@Override
public void run() {
//循环消费
while(true) {
//使用共享数据Person对象p作为锁
synchronized (p) {
//判断是否有数据
if(!p.flag) {
//如果没有数据,消费者线程就等待
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取共享数据的属性值,作为消费
System.out.println(p.getName()+":"+p.getAge());
//重置共享数据状态
p.flag = false;
//唤醒其他线程
p.notify();
}
}
}
}