线程优先级
-
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
-
线程的优先级用数字表示,范围从1~10
-
Thread.MIN_PRIORITY = 1;
-
Thread.MAX_PRIORITY = 10;
-
Thread.NORM_PRIORITY = 5;
-
-
使用以下方式改变或获取优先级
-
getPriority(). setPriority(int xxx)
-
-
优先级的设定建议在start()调度前
-
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看CPU的调度
public class TestPriority { //主线程默认优先级 public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"---->"+Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread t0 = new Thread(myPriority); Thread t1 = new Thread(myPriority); Thread t2 = new Thread(myPriority); Thread t3 = new Thread(myPriority); Thread t4 = new Thread(myPriority); t0.start(); t1.setPriority(3); t1.start(); t2.setPriority(8); t2.start(); t3.setPriority(Thread.MAX_PRIORITY); t3.start(); t4.setPriority(Thread.MIN_PRIORITY); t4.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); } }
守护(daemon)线程
-
线程分为用户线程和守护线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕
-
如,后台记录操作日志,监控内存,垃圾回收等待
public class TestDaemon { public static void main(String[] args) { You you = new You(); God god = new God(); Thread thread = new Thread(god); thread.setDaemon(true); //默认是false表示是用户线程,正常的线程都是用户线程 thread.start(); //上帝线程启动 new Thread(you).start(); //你 用户线程启动 } } //上帝 class God implements Runnable{ @Override public void run() { while (true){ System.out.println("上帝保佑你"); } } } //你 class You implements Runnable{ @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println("你"+i+"岁了"); } System.out.println("========你无了========"); } }
线程同步
-
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制 synchronized ,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可,存在以下问题:
-
一个线程持有锁会导致其他所有需要此锁的线程挂起;
-
在多线程竞争下,加锁,释放锁会导致比较大的上下文切换和调度延时,引起性能问题;
-
如果一个优先级高的线程等待一个优先级低的线程释放锁 会导致优先级倒置,引起性能问题。
-
三大不安全案例
-
买票
//不安全的买票 public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket,"小明").start(); new Thread(buyTicket,"小红").start(); new Thread(buyTicket,"小刚").start(); } } class BuyTicket implements Runnable{ private int ticketNums = 10; boolean flag = true; //外部停止方式 @Override public void run() { //买票 while (flag){ try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void buy() throws InterruptedException { //判断是否有票 if (ticketNums<=0) { Thread.sleep(100); return; } System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--); } }
-
取钱
//不安全的取钱 //俩个人去银行取钱 public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100,"卡"); Drawing you = new Drawing(account,50,"你"); Drawing girlFriend = new Drawing(account,100,"girlFriend"); you.start(); girlFriend.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); //Thread.currentThread().getName() = this.getName() System.out.println(this.getName()+"手里的钱:"+nowMoney); } }
-
线程集合
//线程不安全的集合 public class UnsafeList { public static void main(String[] args) { List<String> list = new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }