现在较为常用的网站开发技术,福建省建设人才与科技发展中心网站首页,千锋教育培训多少钱,提供网站建设收费标准Java 线程的状态 文章目录 Java 线程的状态线程的基础状态1 常见方法1.1 休眠1.2 放弃1.3 加入1.4 优先级1.5 线程打断1.6 守护线程1.7 线程的状态 - 等待 2 线程安全问题2.1 线程同步: 同步代码块2.2 线程同步: 同步方法2.3 同步规则2.4 线程的状态 - 阻塞2.5 特殊现象: 死锁 …Java 线程的状态 文章目录 Java 线程的状态线程的基础状态1 常见方法1.1 休眠1.2 放弃1.3 加入1.4 优先级1.5 线程打断1.6 守护线程1.7 线程的状态 - 等待 2 线程安全问题2.1 线程同步: 同步代码块2.2 线程同步: 同步方法2.3 同步规则2.4 线程的状态 - 阻塞2.5 特殊现象: 死锁 线程的基础状态 初始状态(New) : 线程对象被创建即为初始状态。只在堆中开辟内存与常规对象无异。
就绪状态(Ready) : 调用start()之后进入就绪状态。等待OS选中并分配时间片。
运行状态(Running) : 获得时间片之后进入运行状态如果时间片到期则回到就绪状态。
终止状态(Terminated) : 主线程main()或独立线程run()结束进入终止状态并释放持有的时间片。
1 常见方法
1.1 休眠
public static void sleep(long millis)当前线程主动休眠 millis 毫秒不再参与CPU竞争直达休眠结束。
eg
public class TestSleep {public static void main(String[] args) {SleepThread s1 new SleepThread();SleepThread s2 new SleepThread();s1.start();s2.start();}static class SleepThread extends Thread {Overridepublic void run() {for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName()...i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}1.2 放弃
public static void yield()当前线程主动放弃时间片回到就绪状态竞争下一次时间片。
eg
public class TestYield {public static void main(String[] args) {YieldThread y1 new YieldThread();YieldThread y2 new YieldThread();y1.start();y2.start();}static class YieldThread extends Thread{Overridepublic void run() {for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName()...i);//主动放弃CPUThread.yield();}}}
}1.3 加入
public final void join()允许其他线程加入到当前线程中。当前线程会阻塞直到加入线程执行完毕。
内存分析: eg
public class TestJoin {public static void main(String[] args) throws InterruptedException {JoinThread j1 new JoinThread();j1.start();//把j1加入到主线程中,造成主线程阻塞,直到j1执行完毕j1.join();for (int i 0; i 10; i) {System.out.println(主线程........i);}}static class JoinThread extends Thread {Overridepublic void run() {for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName()...i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}1.4 优先级
线程对象.setPriority(int)线程优先级为1-10默认为5,优先级越高表示获取CPU机会越多。
eg
public class TestPriority {public static void main(String[] args) {PriorityThread p1 new PriorityThread();PriorityThread p2 new PriorityThread();PriorityThread p3 new PriorityThread();//线程优先级为1-10默认为5,优先级越高表示获取CPU机会越多p1.setPriority(1);p3.setPriority(10);//优先级设置要在线程开始之前p1.start();p2.start();p3.start();}static class PriorityThread extends Thread {Overridepublic void run() {for (int i 0; i 100; i) {System.out.println(Thread.currentThread().getName()...i);}}}
}1.5 线程打断
线程对象.interrupt();打断线程被打断线程抛出InterruptedException异常。
eg
public class TestInterrupt {public static void main(String[] args) {InterruptThread thread new InterruptThread();thread.start();System.out.println(10秒内输入任意字符打断子进程休眠);Scanner input new Scanner(System.in);input.next();thread.interrupt();}static class InterruptThread extends Thread{Overridepublic void run() {System.out.println(子线程开始休眠...);try {Thread.sleep(10000);System.out.println(正常醒来);} catch (InterruptedException e) {System.out.println(被打醒了);}}}
}1.6 守护线程
线程有两类用户线程前台线程、守护线程后台线程。如果程序中所有前台线程都执行完毕了后台线程会自动结束。垃圾回收器线程属于守护线程。setDaemon(true)设置为守护线程。
eg
public class TestDaemon {public static void main(String[] args) throws InterruptedException {DaemonThread daemonThread new DaemonThread();//设置守护线程daemonThread.setDaemon(true);//默认false,关闭daemonThread.start();for (int i 0; i 10; i) {System.out.println(主线程....i);Thread.sleep(1000);}}static class DaemonThread extends Thread {Overridepublic void run() {for (int i 0; i 20; i) {System.out.println(Thread.currentThread().getName()...i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}1.7 线程的状态 - 等待 2 线程安全问题 需求A线程将“Hello”存入数组B线程将“World”存入数组。 线程不安全
当多线程并发访问临界资源时如果破坏原子操作可能会造成数据不一致。临界资源共享资源一次仅允许一个线程使用才可保证其正确性。原子操作不可分割的多步操作被视作一个整体其顺序和步骤不可打乱或缺省。
2.1 线程同步: 同步代码块
同步一个线程接着一个线程等待执行。异步多个线程并发同时执行。
语法:
同步代码块
synchronized(锁对象){ //使用共享资源对象加锁//同步代码原子操作
}eg:
4个窗口共卖1000张票Ticket:
public class Ticket implements Runnable{private int count 1000; //票数Overridepublic void run() {while (true) {//一般选择共享资源synchronized (this) { //锁, 任何引用类型的对象都可以作为锁,但要保证唯一性if (count0) {break;}System.out.println(Thread.currentThread().getName() 卖了第 count 张票);count--;}}}
}Test:
public class Test {public static void main(String[] args) {Ticket ticket new Ticket();new Thread(ticket,窗口1).start();new Thread(ticket,窗口2).start();new Thread(ticket,窗口3).start();new Thread(ticket,窗口4).start();}
}注意:
任何的引用类型对象都可以作为锁但是保证多个线程使用唯一对象一般使用共享资源作为锁。每个对象都有一个互斥锁标记用来分配给线程的只有拥有对象互斥锁标记的线程才能进入同步代码。线程退出同步代码块时会释放相应的互斥锁标记。
2.2 线程同步: 同步方法
语法:
同步方法
synchronized 返回值类型 方法名称(形参列表){ //对当前对象this加锁// 代码原子操作
}eg:
4个窗口共卖1000张票Ticket:
public class Ticket implements Runnable{private int count 1000;Overridepublic void run() {while (true) {if (!sale()) {break;}}}//同步方法public synchronized boolean sale() {if (count0) {return false;}System.out.println(Thread.currentThread().getName() 卖了第 count 张票);count--;return true;}
}注意:
只有拥有对象互斥锁标记的线程才能进入该对象加锁的同步方法中。线程退出同步方法时会释放相应的互斥锁标记。如果当前方法是非静态方法锁是this如果方法是静态方法锁是类名.class
2.3 同步规则
注意
只有在调用包含同步代码块的方法或者同步方法时才需要对象的锁标记。如调用不包含同步代码块的方法或普通方法时则不需要锁标记可直接调用。
已知JDK中线程安全的类
StringBufferVectorHashtable以上类中的公开方法均为synchonized修饰的同步方法。
eg:
你和你女朋友共用一张银行卡你向卡中存钱你女朋友从卡中取钱使用程序模拟过程?BankCard:
public class BankCard {private double money;public double getMoney() {return money;}public void setMoney(double money) {this.money money;}
}Test:
public class Test {public static void main(String[] args) {BankCard card new BankCard();//匿名内部类Runnable save new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {synchronized (card) {card.setMoney(card.getMoney() 1000);System.out.println(Thread.currentThread().getName()存了1000, 余额为card.getMoney());}}}};//匿名内部类Runnable take new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {synchronized (card) {if (card.getMoney() 1000) {card.setMoney(card.getMoney() - 1000);System.out.println(Thread.currentThread().getName()取了1000, 余额为card.getMoney());} else {System.out.println(赶紧存钱...);i--;}}}}};new Thread(save,小明).start();new Thread(take,小红).start();}
}2.4 线程的状态 - 阻塞 注JDK5之后就绪、运行统称Runnable
2.5 特殊现象: 死锁
死锁:
当第一个线程拥有A对象锁标记并等待B对象锁标记同时第二个线程拥有B对象锁标记并等待A对象锁标记时产生死锁。一个线程可以同时拥有多个对象的锁标记当线程阻塞时不会释放已经拥有的锁标记由此可能造成死锁。
eg:
吃饭问题Test:
public class TestDeadLock {public static void main(String[] args) {new Boy().start();new Girl().start();}static class Lock {static Object LockA new Object();static Object LockB new Object();}static class Boy extends Thread {Overridepublic void run() {synchronized (Lock.LockA) {System.out.println(Boy拿到了A锁);synchronized (Lock.LockB) {System.out.println(Boy拿到了B锁);System.out.println(Boy可以吃饭了);}}}}static class Girl extends Thread {Overridepublic void run() {synchronized (Lock.LockB) {System.out.println(Girl拿到了B锁);synchronized (Lock.LockA) {System.out.println(Girl拿到了A锁);System.out.println(Girl可以吃饭了);}}}}
}情况一: 死锁
Boy拿到了A锁
Girl拿到了B锁情况二: 未死锁
Boy拿到了A锁
Boy拿到了B锁
Boy可以吃饭了
Girl拿到了B锁
Girl拿到了A锁
Girl可以吃饭了