线程的状态
- java中的线程共五个状态:新建、就绪、运行、阻塞、死亡;
- 新建状态(New):处于系统创建线程,但未启动此线程,系统未为其分配资源。
- 就绪状态(Runnable):线程调用start( )方法,线程转为就绪状态,线程获取(除CPU以外)系统资源。同时该线程位于可运行线程池中,变得可运行,等待调度程序调度。
- 运行状态(Running):线程获得CPU时间,进入运行状态,开始执run()方法。
- 阻塞状态(Blocked):系统让出CPU进入阻塞状态,可根据特定的方法返回可运行状态。
- 死亡状态(Dead):线程执行完毕或异常退出run( )方法,线程结束生命周期。
线程的调度
-
在多个CPU的计算机中,线程数多余CPU的个数,为了防止因线程争夺资源,而导致系统死机或崩溃,Java中定义了线程的优先级控制和调整策略。
-
优先级控制: Java将优先级分为10个等级,数字越大优先级越高。静态常量MIN_PRIORITY、NORMAL_PRIORITY、MAX_PRIORITY;
- void setPriority(int newPriority):设置(改变)线程的优先级。
- int getPriority():得到线程的优先级。
-
线程的调度策略:
1.分时调度模型:线程轮流获取cpu的使用权,采用时间片均匀分配的方式。
2.抢占式调度模型:以优先级高的线程占用CPU为标准,直至线程自己放弃。
注:Java虚拟机采用抢占式调度模型 -
参考代码:
public class PriorityTest {
public static void main(String[] args){
PriorityTestThree r = new PriorityTestThree();
Thread testOne = new Thread(r,"线程1");
// 设置优先级
testOne.setPriority(Thread.NORM_PRIORITY - 2);
testOne.start();
Thread testTwo = new Thread(r,"线程2");
// 设置优先级
testTwo.setPriority(Thread.NORM_PRIORITY + 2);
testTwo.start();
}
static class PriorityTestThree implements Runnable{
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i<4;i++){
System.out.println(Thread.currentThread().getName() + ":" +i);
}
System.out.println(Thread.currentThread().getName() + ":完成!");
}
}
}
- 控制台输出结果:
线程2:0
线程2:1
线程2:2
线程2:3
线程1:0
线程2:完成!
线程1:1
线程1:2
线程1:3
线程1:完成!
线程的同步
-
线程同步: 指当一个临界资源被线程访问时,其它线程不能对该资源访问;直至该线程访问结束,其他线程才方可访问该临界资源。
-
适用场景: 一些敏感资源不能被多个线程临时访问时,适用同步访问技术,来保障数据的安全性和准确性。
-
同步化的两种方法: 同步方法和同步代码块。
- 同步方法:使用
synchronized
关键字修饰需要同步的方法。该方法会自动被加上内置锁。public synchronized 类型 方法名(参数表) { // 方法体 }
- 同步代码块:即用
synchronzied
关键字修饰的语句块,该语句块会自动被加上内置锁。synchronize (object){ // 语句块 }
- 同步方法:使用
-
以银行存款为例:
- 参考代码:
public class BankThreadTest implements Runnable {
private static Bank bank;
BankThreadTest(Bank bank){
this.bank = bank;
}
public void run(){
for(int i=0;i<3;i++){
bank.save(100);
}
}
public static void main(String[] args){
bank = new Bank();
BankThreadTest s = new BankThreadTest(bank);
Thread threadOne = new Thread(s);
threadOne.start();
Thread threadTwo = new Thread(s);
threadTwo.start();
}
static class Bank{
private int money = 0;
// 设置同步方法
public synchronized void save(int money){
int temp = this.money;
temp += money;
try{
// 设置休眠时间
Thread.sleep((int)(Math.random()*1000));
}catch(InterruptedException e){
e.printStackTrace();
}
this.money = temp;
String n = Thread.currentThread().getName();
System.out.println(n + ":存入"+ money + "元,账户余额为:"+ this.money);
}
}
}
- 控制台输出结果:
Thread-0:存入100元,账户余额为:100
Thread-0:存入100元,账户余额为:200
Thread-0:存入100元,账户余额为:300
Thread-1:存入100元,账户余额为:400
Thread-1:存入100元,账户余额为:500
Thread-1:存入100元,账户余额为:600
- 不使用
synchronized
方法下的代码:
public class BankThreadTest implements Runnable {
private static Bank bank;
BankThreadTest(Bank bank){
this.bank = bank;
}
public void run(){
for(int i=0;i<3;i++){
bank.save(100);
}
}
public static void main(String[] args){
bank = new Bank();
BankThreadTest s = new BankThreadTest(bank);
Thread threadOne = new Thread(s);
threadOne.start();
Thread threadTwo = new Thread(s);
threadTwo.start();
}
static class Bank{
private int money = 0;
public void save(int money){
//synchronized
int temp = this.money;
temp += money;
try{
Thread.sleep((int)(Math.random()*1000));
}catch(InterruptedException e){
e.printStackTrace();
}
this.money = temp;
String n = Thread.currentThread().getName();
System.out.println(n + ":存入"+ money + "元,账户余额为:"+ this.money);
}
}
}
- 控制类输出结果:
Thread-1:存入100元,账户余额为:100
Thread-0:存入100元,账户余额为:100
Thread-1:存入100元,账户余额为:200
Thread-0:存入100元,账户余额为:200
Thread-1:存入100元,账户余额为:300
Thread-0:存入100元,账户余额为:300