线程
创建一个线程 相当于cpu开辟了独立的运行执行路径
每个执行路径都是独立空间
创建一个线程 该线程就会有一个独立栈空间
如果在同一个栈空间 不符合 先入栈的后出栈的规则
线程的六种状态:
- 新建状态(new 线程对象)
- 运行状态(调用start方法)
- 受阻塞状态(等待cpu的执行资源)
- 休眠状态(调用sleep(时间)方法)
- 等待状态(调用wait方法)
- 死亡状态(run方法执行完毕)
匿名内部类方式
相当于创建一个该类的子类的对象
new 父类名或接口名(){
重写父类的方法
};
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
});
thread.start();
new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}.start();
}
线程休眠
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
Thread.sleep(666);
System.out.println(Thread.currentThread().getName() + " - " + i);
}
}
class SleepThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(666);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " - " + i);
}
}
}
同步锁
锁可以是任意对象 要保证锁的唯一 多个线程使用的是同一把锁
synchronized(对象锁) {
}
同步锁规则:
线程 遇到锁 就进 同步代码块 (携带锁)
当线程 执行完代码块中的代码 把锁返还
线程 没有遇到锁 会在同步代码块外等着 遇到锁才能进
卖火车票问题
public static void main(String[] args) {
tick tickets = new tick();
Thread one = new Thread(tickets,"人工");
Thread two = new Thread(tickets,"12306");
Thread three = new Thread(tickets,"手机app");
one.start();
two.start();
three.start();
}
class Tickets implements Runnable{
private int num = 50;
Object mutex = new Object();
@Override
public void run() {
while (true) {
synchronized (this) {
if (num > 0) {
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还剩" + num--);
} else {
System.out.println("没票了");
break;
}
}
Thread.yield();
}
}
}
public static void main(String[] args) {
tick tickets = new tick();
Thread one = new Thread(tickets,"人工");
Thread two = new Thread(tickets,"12306");
Thread three = new Thread(tickets,"手机app");
one.start();
two.start();
three.start();
}
class tick implements Runnable{
private int num = 50;
Object mutex = new Object();
@Override
public void run() {
while (true) {
if (sellTikes()) {
break;
}
Thread.yield();
}
}
public synchronized boolean sellTikes() {
if (num > 0) {
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还剩" + num--);
return false;
} else {
System.out.println("没票了");
return true;
}
}
}
死锁
线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2 接下来 当线程A仍然持有lock1时 它试图获取lock2
因为线程B正持有lock2 因此线程A会阻塞等待线程B对lock2的释放 如果此时线程B在持有lock2的时候
也在试图获取lock1 因为线程A正持有lock1 因此线程B会阻塞等待A对lock1的释放
二者都在等待对方所持有锁的释放 而二者却又都没释放自己所持有的锁
这时二者便会一直阻塞下去 这种情形称为死锁
模拟死锁
public static void main(String[] args) {
DeadThread deadThread = new DeadThread();
Thread thread = new Thread(deadThread);
Thread thread1 = new Thread(deadThread);
thread.start();
thread1.start();
}
class LockA {
private LockA() {
}
public static final LockA LOCK_A = new LockA();
}
class LockB {
private LockB() {
}
public static final LockB LOCK_B = new LockB();
}
class DeadThread implements Runnable{
private boolean isTrue = true;
@Override
public void run() {
while (true) {
if (isTrue) {
synchronized (LockA.LOCK_A) {
System.out.println("if...LOCK_A");
synchronized (LockB.LOCK_B) {
System.out.println("if...LOCK_B");
}
}
}else {
synchronized (LockB.LOCK_B) {
System.out.println("if...LOCK_B");
synchronized (LockA.LOCK_A) {
System.out.println("else...LOCK_A");
}
}
}
isTrue = !isTrue;
}
}
}
Lock 接口
使用lock锁
lock.lock();
try{
操作共享数据的代码
} finally{
lock.unlock();
}
接口实现创建线程的好处:
避免了直接继承
Thread类的局限性(避免单继承)
public static void main(String[] args) {
Titkets3 titkets3 = new Titkets3();
Thread t1 = new Thread(titkets3);
Thread t2 = new Thread(titkets3);
Thread t3 = new Thread(titkets3);
t1.start();
t2.start();
t3.start();
}
class Titkets3 implements Runnable{
private int titkets = 50;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
try {
if (titkets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + titkets--);
} else {
break;
}
} finally {
lock.unlock();
}
Thread.yield();
}
}
}