线程03
1、观察线程状态
//观察测试线程状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
//线程执行体
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("......");
});
//观察状态
Thread.State state = thread.getState();
System.out.println(state);//NEW
//观察启动
thread.start();//启动线程
state = thread.getState();//持续观察线程
System.out.println(state);//RUNNABLE
while (state != Thread.State.TERMINATED){//只要线程不终止,就一直打印状态
Thread.sleep(100);
state = thread.getState();//更新线程状态
System.out.println(state);
}
}
}
- 一个线程结束后不能再次启动
2、线程的优先级
- 设置优先级提高了CPU调度的可能性,但不是一定优先调度优先级高的线程
public class TestPriority {
public static void main(String[] args) {
//主线程默认优先级
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
//先设置优先级在启动
//1~10,越大优先级越高
t1.start();
t2.setPriority(Thread.MIN_PRIORITY);//1
t2.start();
t3.setPriority(Thread.NORM_PRIORITY);//5
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);//10
t4.start();
}
}
3、静态代理
- 真实对象和代理对象都要实现同一个接口
- 代理对象能做更多的事
- 真实对象只需做自己专注的事
//静态代理
//代理能做许多自己本身做不到的事
public class StaticProxy {
public static void main(String[] args) {
You you = new You();//你
WeddingCompany weddingCompany = new WeddingCompany(you);//你去婚庆公司办婚礼
weddingCompany.HappyMarry();//婚庆公司帮你解决
}
}
//结婚的接口,你与婚庆公司都要做的事。但婚庆公司还能帮你做其他事
interface Marry {
void HappyMarry();
}
//你结婚
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("你要结婚了");
}
}
//婚庆公司帮你办好结婚
class WeddingCompany implements Marry{
private Marry target;//结婚的客户
//有参构造,传入目标客户
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();//婚前
this.target.HappyMarry();//你结婚
after();//婚后
}
private void before() {
System.out.println("婚前布置现场");
}
private void after() {
System.out.println("婚后收尾款");
}
}
4、守护(daemon)线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
//守护线程
//上帝守护着你
public class TestDaemon {
public static void main(String[] args) {
Me me = new Me();
God god = new God();
Thread thread = new Thread(god);
thread.setDaemon(true); //默认false,一般线程都是用户线程
thread.start();//守护线程启动
new Thread(me).start();//用户现场启动
}
}
class God implements Runnable {
@Override
public void run() {
//原本该循环是死循环,不会结束,但设置守护线程后,用户线程结束守护线程也会关闭,但需要一些时间
while (true){
System.out.println("上帝守护着我");
}
}
}
class Me implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("我每天开心的活着");
}
System.out.println("========Goodbye World=========");
}
}
5、线程同步机制
-
用到队列和锁
- 队列就是排队,多个线程操作同一个对象时要按顺序来
- 锁就好比排队上公厕,进入厕所后锁门,处理完后在出来
-
先写一个不安全的案例,银行取钱
public class UnsafeBank {
public static void main(String[] args) {
//账户,只有100万
Account account = new Account(100,"买房基金");
//你取钱,50万
Drawing you = new Drawing(account,50,"你");
//你女朋友取钱,100万
Drawing yourGirlfriend = new Drawing(account,100,"你女朋友");
you.start();
yourGirlfriend.start();
}
}
//账户
class Account {
int money;//余额
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行:模拟取款
class Drawing extends Thread{
Account account;//账户
//取了多少钱
int drawingMoney;
//现在的钱
int nowMoney;
public Drawing(Account account,int drawingMoney,String name){
super(name);//谁取钱
this.account = account;
this.drawingMoney = drawingMoney;
}
@Override
public void run() {
//判断有没有钱
if(account.money - drawingMoney < 0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
//用sleep放大问题的发生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额 = 余额 - 你取的钱
account.money = account.money - drawingMoney;
//你手里的钱
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
System.out.println(this.getName()+"手里的钱:"+nowMoney);
}
}
同步方法synchronized,锁
- 锁的是共享资源,要修改的量
- synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
- 缺点就是效率变慢
synchronized(obj){}
- 安全的取钱应该一个人取完在判断该账户的钱是否够下一个人取,而不是同时取
@Override
public void run() {
synchronized(account){//锁的是修改的对象,也就是账户
//判断有没有钱
if(account.money - drawingMoney < 0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
//用sleep放大问题的发生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额 = 余额 - 你取的钱
account.money = account.money - drawingMoney;
//你手里的钱
nowMoney = nowMoney + drawingMoney;
System.out.println(this.getName()+"手里的钱:"+nowMoney);
System.out.println(account.name+"余额为:"+account.money);
}
}
}