线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。什么是多线程呢?即就是一个程序中有多个线程在同时执行。
单线程:即,若有多个任务,只能依次进行。比如去银行取钱,一个ATM机只能排队操作。
多线程:多个任务可以同时进行,例如,银行两个ATM机同时进行存取款。
程序运行原理
分时调度:
所有线程轮流使用CPU,平均分配每个线程使用CPU的使用时间。
抢占式调度:
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
/**
* @Description:
* @Author: Mr'Sun
*/
public class Test {
public static void main(String[] args) {
//new 一个票,被4个窗口共享
Ticket ticket = new Ticket();
new Thread(ticket,"窗口1").start();
new Thread(ticket,"窗口2").start();
new Thread(ticket,"窗口3").start();
new Thread(ticket,"窗口4").start();
}
}
/**
* 实现Runnable的代码
*/
class Ticket implements Runnable {
//设票数为10
int ticket=10;
@Override
public void run() {
while (true){
if (ticket>0){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在售票:"+ticket--);
}
}
}
}
**********************************
run:
窗口4正在售票:2
窗口2正在售票:3
窗口3正在售票:1
窗口1正在售票:0
窗口2正在售票:-2
窗口4正在售票:-1
结果出现了0和负数,这就涉及到了线程安全的问题,
加同步锁 synchronized(Object o){....} o可以是任意对象。
加同步锁后的代码:
class Ticket implements Runnable {
//设票数为10
int ticket=5;
@Override
public void run() {
while (true){
synchronized (this){
if (ticket>0){
try {
Thread.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在售票:"+ticket--);
}
}
}
}
}
************************
run:
窗口1正在售票:5
窗口4正在售票:4
窗口4正在售票:3
窗口4正在售票:2
窗口4正在售票:1
ps:加了同步锁就相当于把被锁住的代码块一次性只能给一个线程调用
线程死锁:
同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。
synchronized (A锁){
synchronized (B锁){
}
}
public class Test {
//创建两个锁,A锁住厕所坑位,B锁住手纸
public static Object locaA = new Object();
public static Object locaB = new Object();
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(ticket, "A").start();
new Thread(ticket, "B").start();
}
}
class Ticket implements Runnable {
//获取随机数0-1
int x = new Random().nextInt(1);
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
synchronized (Test.locaA) {
System.out.println(Thread.currentThread().getName() + "获得蹲坑");
synchronized (Test.locaB) {
System.out.println(Thread.currentThread().getName() + "获得手纸");
}
}
} else {
synchronized (Test.locaB) {
System.out.println(Thread.currentThread().getName() + "获得蹲坑");
synchronized (Test.locaA) {
System.out.println(Thread.currentThread().getName() + "获得手纸");
}
}
}
x++;
}
}
}
****************
run:
A获得蹲坑
A获得手纸
B获得蹲坑
A获得手纸
当其中一个人获得坑位,在获得手纸,程序才能进行下去。
一旦A获得了坑位,而CPU让B获得了手纸,结果A需要手纸才能离开,
而B需要坑位才能进去。所以就互相锁住了(死锁)。
等待唤醒机制
线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即等待唤醒机制