JAVA高级应用之线程详解
线程的六种状态
创建一个线程 相当于cpu开辟了一个独立的执行路径
每个执行路径都是一个空间
创建线程 该线程就会拥有一个独立的栈空间
如果在同一个栈空间中 不符合先入栈和后出栈的规则
状态:
1.新建状态(new 线程对象)
2.运行状态(调用start方法)
3.受阻塞状态(等待cpu的执行资源)
4.休眠状态(调用了sleep(时间)的方法)
5.等待状态(调用了wait方法)
6.死亡状态(run方法执行完毕)
![这里写图片描述](https://img-blog.csdn.net/20180206220324248?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1cm9uZ3NoZW5nMTIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
代码示例
package com.lanou3g.p02;
public class Demo08 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for(int i = 1; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
}
}
}
匿名内部类创建线程
匿名内部类方式
相当于创建了一个该类的子类的对象
new 父类名()或接口名{
重写父类的方法
}
这里new出来的 就是这个类的 子类对象
对学生进行排序-方法一
public class Demo09 {
public static void main(String[] args) {
TreeSet<Student> set = new TreeSet<>(new MyComparator());
set.add(new Student("张飞", 20));
set.add(new Student("关羽",10));
set.add(new Student("刘备", 15));
for (Student student : set) {
System.out.println(student);
}
}
}
class MyComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
对学生进行排序-方法二
public class Demo09 {
public static void main(String[] args) {
Comparator<Student> comparator = new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
};
TreeSet<Student> set = new TreeSet<>(comparator);
set.add(new Student("张飞", 20));
set.add(new Student("关羽",10));
set.add(new Student("刘备", 15));
for (Student student : set) {
System.out.println(student);
}
}
}
对学生进行排序-方法三
public class Demo09 {
public static void main(String[] args) {
TreeSet<Student> set = new TreeSet<>(
new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
set.add(new Student("张飞", 20));
set.add(new Student("关羽",10));
set.add(new Student("刘备", 15));
for (Student student : set) {
System.out.println(student);
}
}
}
创建线程的三种方式
方式一
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "我是方式一");
}
};
thread.start();
}
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "我是方式一");
}
}.start();;
}
方式二
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "我是方式二");
}
};
Thread thread = new Thread(runnable);
thread.start();
}
方式三
public class p10 {
public static void main(String[] args) {
Thread thread = new Thread(
new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "我是方式三");
}
}
);
thread.start();
}
}
public class p10 {
public static void main(String[] args) {
new Thread(
new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "我是方式三");
}
}
).start();
}
}
线程休眠
如果子线程中 出现异常 只能try...catch处理
Thread类是Runnable接口的 实现类
重写方法中的run方法
该方法没有抛出异常
所有Runnable接口的实现类(包括Thread类)
都不能在run方法中抛出异常 只能处理
package com.lanou3g.p02;
public class Demo11 {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "我是主线程" + i);
}
}
}
class MyThread1 implements Runnable{
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 0; i < 50; i++) {
System.out.println(i);
}
}
}
public class Demo11 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(
new Runnable() {
@Override
public void run() {
for(int i = 0; i < 50; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + i);
}
}
}
);
thread.start();
}
}
package com.lanou3g;
public class Demo05 {
public static void main(String[] args) {
TiketsRunnable tRunnable = new TiketsRunnable();
Thread t1 = new Thread(tRunnable);
Thread t2 = new Thread(tRunnable);
Thread t3 = new Thread(tRunnable);
t1.start();
t2.start();
t3.start();
}
}
class TiketsRunnable implements Runnable{
private int tickets = 50;
@Override
public void run() {
while(true) {
synchronized (this) {
if(tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + tickets);
tickets--;
}else {
break;
}
}
Thread.yield();
}
}
}
同步锁
线程 遇到锁 就进 进代码块(携带锁)
当线程 执行完代码块中的代码 就把锁返还
线程 没有遇到锁 会在同步代码块外等着 遇到锁才能进
public class Demo06 {
public static void main(String[] args) {
TiketsRunnable1 tRunnable1 = new TiketsRunnable1();
Thread t1 = new Thread(tRunnable1);
Thread t2 = new Thread(tRunnable1);
Thread t3 = new Thread(tRunnable1);
t1.start();
t2.start();
t3.start();
}
}
class TiketsRunnable1 implements Runnable{
private int tickets = 50;
private Object obj = new Object();
@Override
public void run() {
while(true) {
if (sellTickets()) {
break;
}
Thread.yield();
}
}
public synchronized boolean sellTickets() {
if(tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + tickets);
tickets--;
return false;
}else {
return true;
}
}
}
死锁
死锁是由于争用资源而出现的问题,有两份资源,A线程,拿了一份,B线程也拿了一份,双方都需要对方手里的资源才能执行完自己的线程
而双方又不会主动让出自己的资源,而是拿着自己的资源等待另一份资源,由于两个线程没有完成自己的任务
所以不会释放自己的资源,双方一直等待 造成死锁问题
模拟线程死锁
1.需要两个锁对象(保证唯一)
public class Demo07 {
public static void main(String[] args) {
DieLockRunnable die = new DieLockRunnable();
Thread t1 = new Thread(die);
Thread t2 = new Thread(die);
t1.start();
t2.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 DieLockRunnable 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("else...LOCK_B");
synchronized (LockA.LOCK_A) {
System.out.println("else...LOCK_A");
}
}
}
isTrue = !isTrue;
}
}
}
jdk1.5锁
Lock 接口
使用lock锁
lock.lock();
try{
写操作共享数据的代码
}finally{
lock.unlock();
}
接口实现创建线程的好处:
1.避免了直接继承Thread类的局限性(避免单继承)
2.接口即插即用 减少类与类之间的联系(可以解耦)
package com.lanou3g.p02;
import java.util.concurrent.locks.ReentrantLock;
public class Demo15 {
public static void main(String[] args) {
Tickets tickets = new Tickets();
Thread thread = new Thread(tickets);
Thread thread2 = new Thread(tickets);
Thread thread3 = new Thread(tickets);
thread.start();
thread2.start();
thread3.start();
}
}
class Tickets implements Runnable{
private int tickets = 50;
private ReentrantLock ree = new ReentrantLock();
@Override
public void run() {
while(true) {
ree.lock();
try {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets > 0) {
System.out.println(Thread.currentThread().getName() + " " + tickets);
tickets--;
}else {
break;
}
}finally {
ree.unlock();
}
Thread.yield();
}
}
}