二、线程安全的集合
三、死锁
四、线程通信
五、生产者消费者
六、线程池
创建线程的几种方式 1) 继承 2) 实现Runnable 3) callable接口 Future接口 4) 线程池
启动线程的方法 start()
线程的几种状态
什么是线程不安全
setName getName
Thread.currentThread()
join
sleep
synchronized
售卖后车票
package com.qf.homework;public class Window implements Runnable {// 票(加static,被该类所有对象共享)private static int ticket = 100;// 售票任务@Overridepublic void run() {while (true) {synchronized (Window.class) {if (ticket > 0) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace( );}System.out.println(Thread.currentThread( ).getName( ) + "有余票,正在售出" + ticket);ticket--;} else {System.out.println("票已售完");return;}}}}
}
public static void main(String[] args) {new Thread( new Window() ,"窗口1").start();new Thread( new Window() ,"窗口2").start();new Thread( new Window() ,"窗口3").start();}
StringBuffer是线程安全的,是因为每个方法都加上synchronized,即都是同步方法
StringBuilder没有加
ArrayList是线程不安全
Vector 是线程安全
HashMap 是线程不安全
Hashtable 是线程安全
比HashMap安全,比Hashtable快,即安全又快的集合ConcurrentHashMap[很重要]
死锁: 互相持有对方的锁还不释放
public class MyLock {static Object zuo = new Object();static Object you = new Object();
}
public class Boy extends Thread{@Overridepublic void run() {synchronized (MyLock.zuo){System.out.println("男朋友-拿到左筷子" );synchronized (MyLock.you) {System.out.println("男朋友-拿到右筷子,开吃" );}}}
}
public class Girl extends Thread{@Overridepublic void run() {synchronized (MyLock.you){System.out.println("女朋友-拿到右筷子" );synchronized (MyLock.zuo) {System.out.println("女朋友-拿到左筷子,开吃" );}}}
}
public class TestDeadLock {public static void main(String[] args) {new Boy().start();new Girl().start();}
}
男生先拿到zuo锁,再去获得you锁即可吃饭
但是you锁在女生那里,女生需要获得zuo锁才能吃饭
即 男生需要的you锁被女生拿着,女生需要的zuo锁被男生拿着
互相持有对方的锁,还不释放,就会出现"死锁" 程序卡死,不往下执行,持续阻塞
线程通信,就是线程之间产生联系.
即通知,例如线程A执行到一定时候会
停下
,同时通知另外的线程B执行,
线程B执行到一定时候,也停下,通知线程A执行
以上操作需要Object类的方法
- wait() 让当前线程等待
- notify() 唤醒一个处于等待状态的线程
特殊的:
- wait和notify方法需要在同步方法或者同步代码块内执行
- wait会让当前线程进入等待状态,让出资源,其他线程可以执行
问 wait和sleep有什么区别?
答:
wait是Object类的方法,sleep是Thread类方法
wait和sleep都可以让当前线程进入阻塞状态
但是wait阻塞当前线程,会让出系统资源,其他线程可执行;但是sleep阻塞当前线程,会持有锁不释放,其他线程无法执行
wait需要在同步方法或同步代码快中使用,但是sleep可以在同步或非同步都可以使用
ps: 搞个表格
wait sleep 不同点 属于Object类中的方法,需要再同步代码块或同步方法中。 属于Thread方法,可以同步或不同步的执行。 相同 让线程阻塞,会让出系统资源 让线程阻塞,持有锁不释放资源
问 为什么wait和notify方法要设计在Object类中?
答: 因为锁可以是任意对象,有因为wait和notify需要被 锁对象调用,所以锁对象任意,wait和notify方法也能被任意对象调用,所以就设计在Object类中,因为Object类是所有类的父类
需求: 昨天打印机方法,让print1()和print2()方法交替执行
package com.qf.notify;public class Printer {// 具体哪台打印机执行的标志private int flag = 1;// 现在使用同步方法,print1和print2方法由同一个对象打印机对象调用// print1方法和print2方法锁是同一个,是this,即打印机对象public synchronized void print1() {if (flag != 1) {try {// 锁是谁,就用谁调用wait// 当前线程就陷入等待,会让出资源释放锁this.wait();} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("1 ");System.out.print("2 ");System.out.print("3 ");System.out.print("4 ");System.out.print("\r\n");// 干完活,修改标志flag = 2;// 通知另外一个处于等待状态的线程// 锁是谁,用谁调用方法this.notify();}public synchronized void print2() {if (flag != 2) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("A ");System.out.print("B ");System.out.print("C ");System.out.print("D ");System.out.print("\r\n");flag = 1;this.notify();}
}
// 测试
public class TestNotify {public static void main(String[] args) {Printer printer = new Printer( );new Thread(){@Overridepublic void run() {while (true){printer.print1();}}}.start();new Thread(){@Overridepublic void run() {while (true){printer.print2();}}}.start();}
}
换用同步代码块实现
package com.qf.notify;public class Printer {// 锁对象private Object obj = new Object();// 具体哪台打印机执行的标志private int flag = 1;// 现在使用同步方法,print1和print2方法由同一个对象打印机对象调用// print1方法和print2方法锁是同一个,是this,即打印机对象public void print1() {// 同步代码块,现在锁是字节码文件synchronized(Printer.class) {if (flag != 1) {try {// 锁是谁,就用谁调用wait// 当前线程就陷入等待,会让出资源释放锁// 用字节码锁来调用wait方法Printer.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("1 ");System.out.print("2 ");System.out.print("3 ");System.out.print("4 ");System.out.print("\r\n");// 干完活,修改标志flag = 2;// 通知另外一个处于等待状态的线程// 只能唤醒在此对象监视器(加过锁的)上等待的单个线程.// 如果没有加锁,直接调用该方法唤醒线程,会报错IllegalMonitorStateException// 锁是谁,用谁调用方法Printer.class.notify( );}}public void print2() {synchronized( Printer.class) {if (flag != 2) {try {Printer.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("A ");System.out.print("B ");System.out.print("C ");System.out.print("D ");System.out.print("\r\n");flag = 1;Printer.class.notify( );}}
}
- void start() 开启线程
- void run() 执行线程的方法- run() 方法是start开启线程后,JVM自动调用
- void setName(String name) 给线程设置名字
- String getName() 获得线程的名字
- static Thread currentThread() 返回当前正在执行的线程对象
- setPriority(int priority) 设置优先级- 级别是1-10 ,默认是5
- getPriority() 获得优先级
- join() 加入线程,等待该线程终止
- join(int milles) 加入线程,最大等待直到毫秒数
- void setDaemon(boolean on) 设置守护线程
- static void yield() 礼让线程,暂停当前线程,让其他线程执行
- static void sleep(long milles) 线程休眠
- void stop() 结束当前线程,线程死亡
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NV4f7qWm-1678065007263)(D:\前锋学习笔记\笔记\image-20230306090803972.png)]