线程与线程安全,生产消费者模型
线程与进程
2390. 从字符串中移除星号
给你一个包含若干星号
*
的字符串s
。在一步操作中,你可以:
- 选中
s
中的一个星号。- 移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。
返回移除 所有 星号之后的字符串**。**
注意:
- 生成的输入保证总是可以执行题面中描述的操作。
- 可以证明结果字符串是唯一的。
示例 1:
输入:s = "leet**cod*e" 输出:"lecoe" 解释:从左到右执行移除操作: - 距离第 1 个星号最近的字符是 "leet**cod*e" 中的 't' ,s 变为 "lee*cod*e" 。 - 距离第 2 个星号最近的字符是 "lee*cod*e" 中的 'e' ,s 变为 "lecod*e" 。 - 距离第 3 个星号最近的字符是 "lecod*e" 中的 'd' ,s 变为 "lecoe" 。 不存在其他星号,返回 "lecoe" 。
StringBuilder内置加,删。
- 复习
- 方案一:先放进去在扫描
- 方案二:一个个放,遇到*删除and弹出栈顶。
- 方案三:放到Stringbuilder
引入
- cpu主要用于寻址。
- 摩尔定律
是由英特尔(Intel)创始人之一戈登·摩尔(Gordon Moore)提出来的。其内容为:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。这一定律揭示了信息技术进步的速度。 尽管这种趋势已经持续了超过半个世纪,摩尔定律仍应该被认为是观测或推测,而不是一个物理或自然法。预计定律将持续到至少2015年或2020年。然而,2010年国际半导体技术发展路线图的更新增长已经放缓在2013年年底,之后的时间里晶体管数量密度预计只会每三年翻一番。
进程是任务,线程是分配任务。
进程
并发与并行:
多线程的缺点:管理不便。
new,start(创建,就绪),运行,堵塞,自然死亡。
package com.ffyc.thread;/*** 写10个1~10* 分任务!* @param args*/public class ThreadDemo02 extends Thread{public static void main(String[] args) {Thread t1 = new ThreadDemo02();Thread t2 = new ThreadDemo02();t2.start();//readyt1.start();//就绪,CPU有时间片才会运行,也不是一定运行。}@Overridepublic void run() {for (int i = 1; i <=10 ; i++) {System.out.print(i+"\t");}System.out.println();}
}
线程生命周期
*核心
package com.ffyc.thread;/*** Runnable接口实现(可以继承)* why:java单继承、多实现*/
public class ThreadDemo03 implements Runnable{private String name;public ThreadDemo03(String name) {this.name = name;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(this.name+"-->"+i);}}public static void main(String[] args) {Thread t1 = new Thread(new ThreadDemo03("A"));Thread t2 = new Thread(new ThreadDemo03("B"));t2.start();t1.start();}
}
Runnable
-
对比函数式接口 VS 匿名内部类(接口在内部实现)
-
点灰色–>lambda表示式
-
lambda表示式
-
List排顺序Camparator o1 - o2;逆序 o2- o1。
-
二维数组排序
package com.ffyc.thread;import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;public class SortDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();//动态数组list.add(1);list.add(3);list.add(2);System.out.println(list);//无序:1 3 2 //自己写排序【empty】// OR jdk排list.sort(new A());//写一个A排序System.out.println("Sort:"+list);list.sort(new Comparator<Integer>() {//lambda@Overridepublic int compare(Integer f, Integer l) {return f-l;}});System.out.println("first-last:"+list);}
}
package com.ffyc.thread;public class ThreadDemo05 {public static void main(String[] args) {/*** Runnable匿名内部类*/Thread t1 = new Thread(new Thread(() -> {for (int i=1;i<10;i++){System.out.println("A->"+i);}}));Thread t2 = new Thread(new Thread(() -> {for (int i=1;i<20;i++){System.out.println("B->"+i);}}));t1.start();t2.start();}
}
block():阻塞
三种解决方法:
- sleep()–>唤醒前要就绪
- yield
- join
- wait——高级别–》对all对象
可怕
List扩容时可能加入新的元素,不安全。
守护线程和用户线程
守护最后一个用户线程结束才结束。
守护线程–> .setDaemon(true)
package com.ffyc.thread;import java.text.SimpleDateFormat;
import java.util.Date;/*** 守护线程*/
public class ProtectThread {public static void main(String[] args) {Thread t1 = new Thread(()->{while (true){try {Date d = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");System.out.println(sdf.format(d));Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(()->{for (int i = 0; i < 100; i++) {try {System.out.println("我是00"+i);Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.setDaemon(true);t1.start();t2.start();}}
用户线程
复习:
- 线程
- 集合
- 面向对象
线程安全
回顾生命周期
三大特性
- 原子性(理论上)——线程任务不可再分。
- 可见性——线程之间的操作互相不可见。
- 有序性——程序运行顺序不能改变。
特性一:原子性 代码举例
int i = 1;
i++;
原子类–多线程时±/*安全。
AtomicXXX
package com.ffyc.Thread;import java.util.concurrent.atomic.AtomicInteger;/*** 特性一:原子性* i++/++i ===> 不安全---why:两步完成。 */ public class ThreadDemo01 {//static int x = 1;static AtomicInteger a = new AtomicInteger(1);public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(a.addAndGet(1));try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {System.out.println(a.addAndGet(1));Thread.sleep(100);}} catch (InterruptedException e) {throw new RuntimeException(e);}}});// 启动线程t1.start();t2.start();} }
特性二:互盲
但不能保证有序。
Eg:
升级
package com.ffyc.thread;public class ThreadDemo02 {static volatile boolean flag = false;public static void main(String[] args) {//线程A如果,flag为true,就运行打印语句 A: trueThread t1 = new Thread(() -> {while (true) {if (flag) {System.out.println("A:" + flag);}}});//100ms之后将flag变为trueThread t2 = new Thread(() -> {try {Thread.sleep(100);flag = true;System.out.println("B:" + flag);} catch (InterruptedException e) {throw new RuntimeException(e);}});t1.start();t2.start();}
}
特性三:不能改变固有顺序
“重点”解决线程安全方案——*锁🔒
原理
- 每一个对象只有一把锁,
- 每个线程抢锁,先拿到的线程就是锁的持有者。
- 持有锁的线程访问有synchronized标记的方法/代码块
- 离开synchronized,线程releas(释放)锁🔒
现实场景:买票程序
ticket
package com.ffyc.ticket;public class Ticket {private Integer num;private String name;public Ticket(Integer num) {this.num = num;}public Ticket(Integer num, String name) {this.num = num;this.name = name;}/*** 取出剩余票数* @return*/public Integer getNum() {return num;}/*** 卖票* @param name* //sy 同步 解决*/public synchronized void sold(String name){System.out.println("站点"+name+"购买成功,余票"+ (--num)+"票");//why前减}
}
tivketThread
package com.ffyc.ticket;public class TicketsThread extends Thread{private final String name;private final Ticket ticket;public TicketsThread(Ticket ticket,String name){this.ticket=ticket;this.name = name;}@Overridepublic void run(){// synchronized (ticket.getNum()){//解决-1,-2票的打印问题,但是全是A买的。while (ticket.getNum()>2){//笨办法解决try {sleep(100);ticket.sold(name);} catch (InterruptedException e) {throw new RuntimeException(e);}}}//}}
TicketTest
package com.ffyc.ticket;public class TestTicket {public static void main(String[] args) {Ticket ticket = new Ticket(100);Thread a = new TicketsThread(ticket, "A");Thread b= new TicketsThread(ticket,"B");Thread c = new TicketsThread(ticket,"C");a.start();c.start();b.start();}
}
Ways:
- 方法体
- 方法里**{代码块},注意不能有基本数据类型,要用包装类型。**
改造Atomic
sy联系:StringBuffer,Vector。
Asy异步 ——》 前端里用
持有锁
死锁
sy(A){
sy(B){ }
}
Resource
package com.ffyc.lock;public class Resource {private String name;public Resource(String name) {this.name= name;}public String getName() {return name;}@Overridepublic String toString() {return "Resource{" +"name='" + name + '\'' +'}';}
}
DeadLockThread
package com.ffyc.lock;public class DeadLockThread extends Thread{private Resource x;private Resource y;public DeadLockThread(Resource x, Resource y) {this.x = x;this.y = y;}@Overridepublic void run() {synchronized (x){System.out.println(x.getName()+"锁定"+x.getName()+"成功...");try {sleep(200);System.out.println(x.getName()+"准备--->锁定"+y.getName()+">>>>");synchronized (y){System.out.println(x.getName()+"锁定"+y.getName()+"成功...");}System.out.println("释放"+y.getName()+"成功...");} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("释放"+x.getName()+"成功...");}}
Main
package com.ffyc.lock;public class Main {public static void main(String[] args) {Resource lwh = new Resource("李文豪");Resource wzy = new Resource("隗子垚");Resource fzy = new Resource("冯正阳");Thread a = new DeadLockThread(lwh, fzy);Thread b = new DeadLockThread(fzy, wzy);Thread c = new DeadLockThread(wzy, lwh);a.start();b.start();c.start();}}
leetcode191
int num = 0;String s = Integer.toBinaryString(n);for (int i = 0; i < s.length(); i++) {if (s.charAt(i)=='1') num++;}return num;
生产者消费者模型
hamburger类
HLS
用wait记得抛线程异常。
消费者consumer