线程:
原理:多线程执行时候,在栈内存中,其实每一个执行线程都有一片所属的栈内存的空间,进行方法的
压栈,和弹栈.
原理图;
Thread类:
构造方法:
常用方法:
|
创建多线程:
多线程三种创建方法:
package com.heima.biji;
|
package com.heima.biji;
|
package com.heima.biji;
|
package com.heima.biji;
|
package com.heima.biji;
|
三种方式各自好处:
继承
|
接口
匿名内部内
使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。 |
实现Runnable接口比继承Threed类所具有的优势
1.适应多个相同的程序代码的线程去共享一个资源.2.可以避免java中的单继承的局限性.3.增加程序的健壮性,实现解耦操作,任务可以被多个线程共享,任务和线程独立.4.线程池只能放入实现Runnable或Callable类线程,不能直接放入继承Thread的类耦合性:类和类之间的相互影响的程度.扩充:在java中,每次程序运行至少启动2个线程,一个是main线程,一个是垃圾收集线程,因为每当使用Java命令执行一个类的时候,一个是垃圾收集线程,因为每当使用Java执行一个类实际东辉启动一个jvm,每个JVM其实都是在操作系统启动一个进程. |
线程安全:
定义:
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 |
实例题目:
线程同步:
当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题解决:解决上诉问题多线程访问一个资源安全性问题,也就是解决重复的问题,java中提供了(synchronized)来解决线程访问使用三种方式完成同步操作1.同步代码快(synchronized)关键字可以用于方法的某个区块中表示区块资源的互斥访问.格式:synchronized(同步锁){需要同步操作的代码}同步锁:对象的同步锁只是一个概念,可以想象为在对象上标志记了一个锁.锁对象(可以是任意数据对象).多个线程对象,要使用同一把锁.注意:在任何时候,最多仍许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLDCKED).2.同步方法3.锁机制 |
同步方法:
同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。public synchronized void method(){可能会产生线程安全问题的代码}同步锁是谁:对于非static方法,同步锁就是this.对于static方法,我们使用当前方法所有类的字节代码对象(类名.class) |
package com.heima.biji;
//同步方法
public class Mythread04 implements Runnable{
private int ticket = 100;//定义电影票的个数
//重写run方法
@Override
public void run() {
//每个窗口买票的过程
//窗口永远在开启
while (true){
sellTicket();
}
}
public synchronized void sellTicket(){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在买:" + ticket-- + "张");
}
}
}
Lock锁:
java.util.concurrent.loks.Lock机制提供了比synchronized代码块,和synchronized方法
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
|
代码快:
package com.heima.biji;
import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//Lock锁
public class Mythread05 implements Runnable {
//设置票数
private int ticket = 100;
Lock lock = new ReentrantLock();
//执行买票操作
@Override
public void run() {
while (true) {
lock.lock();//加同步锁
if (ticket > 0) {//有票可以买
//每个窗口买票的操作
//窗口 永远开启
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在买:" + ticket-- + "票");
}
lock.unlock();//释放同步锁
}
}
}
线程的状态:
当线程被创建并启动后,他既不是一启就进入执行状态,也不是一直处于执行状态:
在线程生命周期中有6种状态.
线程状态 |
导致方式条件 |
NEW(新建) |
线程刚被创建,但是并未启动。还没调用start方法。 |
Runnable(可运行) |
线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。 |
Blocked(锁阻塞) |
当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。 |
Waiting(无限等待) |
一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。通过wait()方法进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。 |
TimedWaiting(计时等待) |
同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。 |
Teminated(被终止) : 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。
Timed Waiting(计时等待):
-
Timed Waiting在API中的描述为:一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态。单独的去理解这句话,真是玄之又玄,其实我们在之前的操作中已经接触过这个状态了,在哪里呢?
代码:题目
**实现一个计数器,计数到100,在每个数字之间暂停1秒,每隔10个数字输出一个字符串** |
package com.heima.biji;
|
通过以上代码发现:
- 进入 TIMED_WAITING 状态的一种常见情形是调用的 sleep 方法,单独的线程也可以调用,不一定非要有协作关系。
- 为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程中会睡眠
- sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。
提示:
sleep()中指定的时间线程不会运行的最短时间,因此,sleep()方法不能保证线程到期后立即执行.
Blocked线程图:
|
Waiting(无限等待):
模拟无限等待:
1.使用锁对象调用wait()方法,则该线程就会进入无限等待状态
2.其他线程使用锁对象调用notify()或者notifyAll()方法,才可以唤醒无限等待
notift()唤醒单个无限等待的线程
notifyAll()唤醒多个无限等待的线程
3.调用wait()和notify()以及notifyAll()方法的锁对象要一致.
4.无限等待,可以切换到可运行或者锁阻塞状态.
package com.heima.biji;
|
线程的有线通信:
补充知识点:
1.多线程的开启:
题目:描述Thread类中的start()方法与run()方法的区别
答:线程对象调用的run()方法不开启线程,仅是对象的调用方法,线程对象调用start()方法启用线程,并jvm调用run()方法在开启的线程中执行. |