线程:
问题
1. 线程有哪几种状态? 分别说明从哪一种状态到另一种状态转变有那些方式?
2. 通常线程有哪几种使用方式
3. 基础线程机制有那些?
4. 线程中断方式有哪些?
5. 线程的互斥同步方式有哪些? 如何比较和选择?
6. 线程之间有哪些协作方式?
线程实现:
1.实现 Runnable 接口 (重点 推荐常用)
/* 步骤: 1. 实现 Runnable 接口 2. 重写 run 3. 执行线程 使用runnable 接口实现类 4. 调用 start 启动线程 */ public class TestRunnable{ public static void main(String[] args){ MyRunnable myRunnable = new MyRunnable(); new Thread(myRunnable).start(); } } class MyRunnable implements Runnable{ @Override public void run(){ System.out.println("run"); } }
2.实现 Callable 接口 (了解即可 不常用)
import java.util.concurrent.Callable; public class TestCallable{ public static void main(String[] args){ MyCallable mc = new MyCallable(); FutureTask<Integer> ft = new FutureTask<>(mc); Thread thread = new Thread(); thread.start(); System.out.println(ft.get()); } } public static class MyCallable implements Callable<Integer>{ @Override public Integer call(){ return 123; } }
3.继承 Thread 方法
/* 继承 Thread 方法 (1) 继承 Thread 方法 (2) 重写 run 方法 (3) 调用 start 方法启动线程 */ public class TestThread { public static void main(String[] args){ MyThread myThread = new MyThread(); myThread.start(); } } class MyThread extends Thread{ @Override public void run(){ System.out.println("run"); } }
推荐使用实现 Runnable 接口
避免了单继承的局限性,方便同一个对象被多个线程使用
不建议使用 继承 Thread 类:
避免出现 OOP 单继承局限性
线程五大状态:
(1) new 新生状态 Thread thread = new Thread(); 线程对象一旦进入就到了新生状态 (2) 就绪状态 当调用 start() 方法,线程立即进入就绪状态,但不意味着立即调度执行 (3) 运行状态 进入运行状态才真正执行线程体的代码块 (4) 阻塞状态 当调用 sleep() , wait() 或则 同步锁定时候,线程进入阻塞状态 (5) dead 线程中断 或 结束,一旦进入死亡状态,就不能再次启动
1. 线程停止
/* 线程停止 stop 停止线程 1. 建议线程自然停止 --> 利用次数,不建议死循环 2. 建议使用标志位 --> 设置一个标志位 3. 不要使用 stop 或者 destroy 等过时的 或者 jdk 不建议使用的方法 */ public class TestThreadStop implements Runnable{ // 1. 设置标志位 private boolean flag = true; @Override public void run(){ int i = 0; while(flag){ System.out.println("Thread" + i++); } } // 2. 设置一个公开的方法停止线程,转换标志位 public void stop(){this.flag = false;} public static void main (String[] args){ TestThreadStop tts = new TestThreadStop(); for(int i = 0; i <= 2000; i++){ System.out.println("main" + i); if(i == 1990){ tts.stop(); System.out.println("停止运行"); } } } }
2. 线程休眠 sleep
/* 线程休眠 sleep sleep 指定当前线程的阻塞的毫秒数 sleep 存在异常 InterruptedException sleep 时间达到后线程进入就绪状态 每个对象都有一个锁, sleep 不会释放锁 模拟延时的作用是: 放大问题的发生性 */ // 模拟抢票 public class TestThreadSleep { // 票数 private int ticketNumbers = 10; @Override public void run(){ while(ture){ if(ticketNumbers <= 0){ break; } try{ Thread.sleep(200);// ms }catch (InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNumbers--+"张票"); } } public static void main(String[] args){ TestThreadSleep tts = new TestThreadSleep(); new Thread(tts,"小虎").start(); new Thread(tts,"小华").start(); new Thread(tts,"小黑").start(); } }
3. 线程礼让 yield
/* 线程礼让 让当前正在执行的线程暂停,但不阻塞 将线程从运行状态转为就绪状态 让 cpu 重新调度,礼让不一定成功,看cpu 调度 */ public class TestThreadYeild { public static void main(String[] args){ MyYeild myYeild = new MyYeild(); new Thread(myThread,"A").start(); new Thread(myThread,"B").start(); } } class MyYeild implements Runnable { @Override public void run(){ System.out.println(Thread.currentThread().getName()+"线程开始"); Thread.yeild(); // 线程礼让 System.out.println(Thread.currentThread().getName()+"线程结束"); } }
4.线程强制执行 join
/* Join Join 合并线程,将线程执行完成后,在执行其他线程,(其他线程阻塞) 相当于插队 */ public class TestThreadJoin implements Runnable{ @Override public void run(){ System.out.println(Thread.currentThread().getName()+":START"); System.out.println(Thread.currentThread().getName()+":END"); } public static void main(String[] args){ TestThreadJoin ttj = new TestThreadJoin(); Thread myThread = new Thread(ttj,"A"); myThread.start(); myThread.join(); new Thread(ttj,"a").start(); new Thread(ttj,"b").start(); } }
5. 观测线程状态
/* NEW 尚未启动的线程状态 RUNNABLE 正在运行的状态 BLOCKED 被阻塞等待监视器锁定的线程处于此状态 WAITING 正在等待另一个线程执行特定动作的线程处于此状态 TIME_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程 TEMINATED 退出 */ public class TestThreadState { 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(); } } }); // 观测状态 Thread.State state = thread.getState(); System.out.println(state); // 观测启动后 thread.start(); System.out.println(thread.getState()); // 只要线程不停止 就一直输出状态 while(state != Thread.State.TERMINATED){ Thread.sleep(100); // 更新状态 state = thread.getState(); System.out.println(state); } } }
6. 线程优先级
/* 线程优先级 线程优先级高只代表运行占比大,不代表运行顺序 Java 提供了一个线程调度器来监控程序中启动后进入就绪状态的所有线程 线程调度器会按照优先级决定应该先调度哪一个线程来执行 优先级: 从 1 - 10 超出范围报错 MIN_PRIORITY = 1; MAX_PRIOTITY = 10; NORM_PRIORITY = 5; 方法: getPriority() setPriority(value) 可能出现问题: 性能倒置: 性能优先级低的比高的先运行 */ public class ThreadPriority { public static void main(String[] args) { // 主线程优先级 默认优先级 System.out.println(Thread.currentThread().getName() + "的优先级" + Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread thread1 = new Thread(myPriority,"t1"); Thread thread2 = new Thread(myPriority,"t2"); Thread thread3 = new Thread(myPriority,"t3"); Thread thread4 = new Thread(myPriority,"t4"); Thread thread5 = new Thread(myPriority,"t5"); Thread thread6 = new Thread(myPriority,"t6"); Thread thread7 = new Thread(myPriority,"t7"); Thread thread8 = new Thread(myPriority,"t8"); Thread thread9 = new Thread(myPriority,"t9"); // 设置优先级 1 - 10 超出范围报错 thread1.setPriority(10); thread2.setPriority(9); thread3.setPriority(8); thread4.setPriority(7); thread5.setPriority(6); thread6.setPriority(4); thread7.setPriority(3); thread8.setPriority(2); thread9.setPriority(1); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); thread6.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "的优先级" + Thread.currentThread().getPriority()); } }
7. 守护线程
/* daemon 守护线程 线程分为 用户线程 和 守护线程 虚拟机 必须保证 用户线程 执行完毕 虚拟机 不用等待 守护线程 执行完毕 */ public class ThreadDaemon { public static void main(String[] args) { userThread userThread = new userThread(); daemon daemon = new daemon(); Thread thread = new Thread(daemon); thread.setDaemon(true); thread.start(); new Thread(userThread).start(); } } class daemon implements Runnable{ @Override public void run() { while(true){ System.out.println("守护线程"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } class userThread implements Runnable { @Override public void run() { System.out.println("用户线程===="); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } }
8. 并发 线程同步, 同步方法, 同步块
/* 并发 线程同步 多个线程控制同一资源 synchronized 锁: 锁谁,锁变化的那个量 (1) 同步方法 synchronized 方法控制"对象"的访问,每个对象对应一把锁 synchronized 方法都必须调用该方法的对象的锁才能执行,否则会线程阻塞 方法一旦执行就独占该锁知道的方法返回时候才释放锁,后面被阻塞的线程才能获得这个锁 (2) 同步块 使用语法: synchronized(obj){} */ public class SynchronizedTest { public static void main(String[] args) { }} /* 1. 不安全线程 例题1: 多人抢票 出现负数,重复 每个线程在自己工作内存交互,内存控制不当会造成数据不一致 */ class BuyTickets { public static void main(String[] args){ UnSynchronizedBuyTicket unSynchronizedBuyTicket = new UnSynchronizedBuyTicket(); new Thread(unSynchronizedBuyTicket,"小米").start(); new Thread(unSynchronizedBuyTicket,"小黑").start(); new Thread(unSynchronizedBuyTicket,"小流").start(); } } class UnSynchronizedBuyTicket implements Runnable { private int TicketNumbers = 10; boolean flag = true; @Override public void run() { while(flag){ try { // 线程不安全 // buy1(); // 线程安全 buy2(); }catch(InterruptedException e){ e.printStackTrace(); } } } /** * 线程不安全 * @throws InterruptedException */ private void buy1() throws InterruptedException { if(TicketNumbers <= 0){ flag = false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "买到了第" + TicketNumbers-- + "张票"); } /** * 线程安全 * @throws InterruptedException */ private synchronized void buy2() throws InterruptedException { if(TicketNumbers <= 0){ flag = false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "买到了第" + TicketNumbers-- + "张票"); } } /** * 不安全线程 * 例2 * 两个人取钱 */ class UnSafeBank{ public static void main(String[] args) { Account account = new Account(100,"基金"); Drawing you = new Drawing(account, 50,"you"); Drawing girl = new Drawing(account, 100,"girl"); you.start(); girl.start(); } } /** * 账户 */ class Account{ /** * 余额 */ int money; /** * 用户名 */ String name; public Account (int money,String name){ this.name = name; this.money = money; } } /** * 银行: 模拟取款 */ 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(){ // 不安全取钱 // drawMoney(); // 同步块 (对象) synchronized (account){ // 判断卡里是否有钱 if(account.money - drawingMoney<0){ System.out.println(Thread.currentThread().getName() + "钱不够"); return; } 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+"块"); } } /** * 不安全取钱 */ public void drawMoney(){ // 判断卡里是否有钱 if(account.money - drawingMoney<0){ System.out.println(Thread.currentThread().getName() + "钱不够"); return; } 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+"块"); } } /** * 线程不安全的集合 ArrayList * 例3 */ class UnsafeList{ public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()-> { // list.add(Thread.currentThread().getName()); synchronized (list) { list.add(Thread.currentThread().getName()); } }).start(); } Thread.sleep(3000); System.out.println(list.size()); } }