static yield() :向调度程序提示当前线程愿意放弃其当前对处理器的使用。
一旦执行此方法 , 就释放CPU的执行权
注意 : yield只是让当前线程暂停一下,让系统的线程调度器重新调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。
public static void yield()
final void join() : 在线程A中通过线程B调用join() , 意味着线程A进入阻塞状态 , 直到线程B执行结束 , 线程A才结束阻塞状态 , 继续执行.
public final void join() throws InterruptedException
public final void join(long millis) 等待该线程终止的时间最长为 millis 毫秒。如果millis时间到,将不再等待。
public final void join(long millis, int nanos) 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
final boolean isAlive() : 测试此线程是否存活。如果一个线程已经启动并且还没有死亡,那么它就是存活的。
public final boolean isAlive()
每个线程都有一定的优先级,同优先级线程组成先进先出队列(先到先服务),使用分时调度策略。优先级高的线程采用抢占式策略,获得较多的执行机会。每个线程默认的优先级都与创建它的父线程具有相同的优先级。
Thread类的三个优先级常量:
getPriority() : 获取线程的优先级 , 返回线程的优先级
public final int getPriority()
setPriority( int newPriority ) : 更改此线程的优先级。 范围[1,10]
参数 : newPriority
- 设置该线程的优级
public final void setPriority(int newPriority)
对生产者Product进行分析
1.如果flag = true,证明此时有包子,则不需要生产,所以生产线程wait
2.否则,flag = false,证明此时没有包子,则需要开始生产了,此时count++,然后开始生产包子
3.生产完以后,应该通知消费线程notify
对消费者Consumer进行分析
1.如果flag = false,则证明此时没有包子了,所以消费者不能消费,需要wait消费线程
2.反之,flag = true,则证明此时有包子,那么消费线程开始工作
3.消费完以后,应该通知生产线程notify
包子铺需要准备两个成员变量
flag来表明是否还有存货
count来标志包子数量
public class BaoZiPu {
private int count;
private boolean flag;
public void getCount() {
System.out.println("消费了第"+count+"个包子");
}
public void setCount() {
count++;
System.out.println("生产了第"+count+"个包子");
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
public BaoZiPu() {
}
}
public class Product implements Runnable{
private BaoZiPu baoZiPu;
public Product(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
public Product() {
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (baoZiPu){
if(baoZiPu.isFlag()==true){
try {
baoZiPu.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
baoZiPu.setCount();
baoZiPu.setFlag(true);
baoZiPu.notify();
}
}
}
}
public class Consumer implements Runnable{
private BaoZiPu baoZiPu;
public Consumer() {
}
public Consumer(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
public BaoZiPu getBaoZiPu() {
return baoZiPu;
}
public void setBaoZiPu(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (baoZiPu){
if(baoZiPu.isFlag()==false){
try {
baoZiPu.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
baoZiPu.getCount();
baoZiPu.setFlag(false);
baoZiPu.notify();
}
}
}
}
public class Test {
public static void main(String[] args) {
BaoZiPu baoZiPu = new BaoZiPu();
Product product = new Product(baoZiPu);
Consumer consumer = new Consumer(baoZiPu);
Thread t1 = new Thread(product);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
public class BaoZiPu {
private int count;
private boolean flag;
public synchronized void getCount() {
if(flag == false){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("消费了第"+count+"个包子");
flag = false;
this.notify();
}
public synchronized void setCount() {
if(flag == true){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
count++;
System.out.println("生产了第"+count+"个包子");
flag = true;
this.notify();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
public BaoZiPu() {
}
}
public class Product implements Runnable{
private BaoZiPu baoZiPu;
public Product(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
public Product() {
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.setCount();
}
}
}
public class Consumer implements Runnable{
private BaoZiPu baoZiPu;
public Consumer() {
}
public Consumer(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
public BaoZiPu getBaoZiPu() {
return baoZiPu;
}
public void setBaoZiPu(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.getCount();
}
}
}
public class Test {
public static void main(String[] args) {
BaoZiPu baoZiPu = new BaoZiPu();
Product product = new Product(baoZiPu);
Consumer consumer = new Consumer(baoZiPu);
Thread t1 = new Thread(product);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
public class BaoZiPu {
private int count;
private boolean flag;
public synchronized void getCount() {
while (flag == false){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("消费了第"+count+"个包子");
flag = false;
this.notifyAll();
}
public synchronized void setCount() {
while (flag == true){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
count++;
System.out.println("生产了第"+count+"个包子");
flag = true;
this.notifyAll();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
public BaoZiPu() {
}
}
public class Product implements Runnable{
private BaoZiPu baoZiPu;
public Product(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
public Product() {
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.setCount();
}
}
}
public class Consumer implements Runnable{
private BaoZiPu baoZiPu;
public Consumer() {
}
public Consumer(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
public BaoZiPu getBaoZiPu() {
return baoZiPu;
}
public void setBaoZiPu(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.getCount();
}
}
}
public class Test {
public static void main(String[] args) {
BaoZiPu baoZiPu = new BaoZiPu();
Product product = new Product(baoZiPu);
Consumer consumer = new Consumer(baoZiPu);
Thread t1 = new Thread(product);
Thread t2 = new Thread(product);
Thread t3 = new Thread(product);
Thread t4 = new Thread(consumer);
Thread t5 = new Thread(consumer);
Thread t6 = new Thread(consumer);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
只需要修改BaoZiPu中的get/set业务代码 , 对进入if 的生产者或消费者被wait()之后 , 当cpu再次分配给他们时 , 需要进行重写判断 , 来继续执行 , 此时wait() 以及执行完毕 , 不再执行else中的语句 , 会重新进行抢锁 .
public class BaoZiPu {
private int count;
private boolean flag;
public synchronized void getCount() {
if(flag == false){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else{
System.out.println("消费了第"+count+"个包子");
flag = false;
this.notifyAll();
}
}
public synchronized void setCount() {
if(flag == true){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else{
count++;
System.out.println("生产了第"+count+"个包子");
flag = true;
this.notifyAll();
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
public BaoZiPu() {
}
}
1.概述:是一个接口,需要new实现类对象
2.实现类:ReentrantLock
3.方法:
lock()获取锁
unlock()释放锁
public class Ticket implements Runnable {
int ticket = 50;
//首先获取lock对象
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
Thread.sleep(100L);
//获取锁
lock.lock();
if(ticket > 0){
System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票");
ticket--;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
//释放锁
lock.unlock();
}
}
}
}
public class Test {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket,"张三");
Thread t2 = new Thread(ticket,"李四");
Thread t3 = new Thread(ticket,"王五");
t1.start();
t2.start();
t3.start();
}
}
1.注意:
a.Lock锁属于轻量级锁,底层实现原理为"乐观锁"(CAS机制 Compare And Swap)
b.乐观锁主要操作变量的
属于悲观锁,当一个线程拿到锁对象之后,其他线程拿不到,执行不了,当一个线程做操作的时候,其他线程操作不了->排队
Lock属于乐观锁 , 使用多个线程操作的是同一个变量
synchronized属于悲观锁 , 使用多个线程操作一段代码
乐观锁 : 线程A在操作变量时 , 允许线程B操作 , 只是会先判断 , 如果有问题 , 就放弃本次操作 , 如果判断没有问题 , 则就正常操作
悲观锁 : 当线程A正在操作的时候 , 不允许线程B执行 , 要等A出来之后B才有可能进入执行
相对来说 , 悲观锁效率比较低 , 乐观锁效率比较高
当多线程操作同一个数据时 , 会出现以下问题 :
1.可见性
i=9,变量i的初始值为9,每一个线程的操作都是减1。两个线程A与B同时访问变量,B先执行i-1,在将结果i=8同步到内存中,A线程也执行i-1,这时i=9的状态就被执行两次,出现线程安全问题。 线程安全问题产生的原因:一个线程对共享数据的修改不能立即被其他线程所见。 解决:给共享的变量加上关键字:volatile
2.有序性
多行代码的编写顺序和编译顺序。-> 问题原因 有些时候,编译器在编译代码时,为了提高效率,会对代码“重排”: .java文件 int a = 0; //第一行 int b = 20; //第二行 int c = a / b; //第三行 在执行第三行之前,由于第一行和第二行的先后顺序无所谓,所以编译器可能会对“第一行”和“第二行”进行代码重排: .class int b = 20; int a = 0; int c = a / b; 但在多线程环境下,这种重排可能是我们不希望发生的,因为:重排,可能会影响另一个线程的结果,所以我们不需要代码进行重排 解决:给共享的变量加上关键字:volatile
3.原子性
指的是一个操作不可中断,即在多线程并发的环境下,一个操作一旦开始,就会在同一个CPU时间片内执行完毕 volatile解决不了原子性问题,所以为了多线程操作同一个数据出现的原子性问题,我们可以使用原子类 Atomicxxx类->xxx代表具体数据类型 -> 原子类的实现原理就是乐观锁
之前来一个线程任务,就需要创建一个线程对象,用完还要销毁线程对象,如果频繁的创建和销毁对象,会耗费内存资源,所以我们就想线程对象能不能循环利用,用的时候从线程池中获取,用完之后归还.
1.创建线程池对象,指定池子中最多能有多少个线程对象,假设2个
2.来了一个线程任务,看池子中有没有线程对象,如果没有,创建线程对象,给线程任务用完之后,还回去
3.来了第二个线程任务,看池子中有没有空闲的线程对象,如果有就拿来用,如果没有,就创建,给线程任务用,用完就还回去.
4.来了第三个线程任务,看池子中有没有空闲的线程对象,如果有就拿来用,如果没有,等待,等之前的线程任务执行完毕了,归还了线程对象,再使用,使用完毕再还回去
1.概述:Executors线程池对象
2.获取:static ExecutorService newFixedThreadPool(int nThreads)
a.参数:指定线程池中最多的线程对象数量
b.返回值:ExecutorService 时管理线程对象的
3.ExecutorService中的方法:
Future<?> submit(Runnable task) 提交一个Runnable任务用于执行
a.返回值:Future接口
用于接收run方法的返回值的,但是run方法没有返回值,所以可以不用Future接收了
4.ExecutorService中的方法:
void shutdown():启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
public class MyRunnable1 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"...正在执行");
}
}
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"...执行了");
}
}
public class Test02 {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new MyRunnable1());
//正常是需要返回值的,返回一个Future对象接收,但是run方法没有返回值所以不需要接收
es.submit(new MyRunnable());
es.submit(new MyRunnable());
//shutdown()启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
es.shutdown();
}
}
1.概述:Callable是一个接口,类似与Runnable
2.方法:
V call() -> 设置线程任务的,类似与run方法
3.call方法和run方法的区别:
相同点:都是设置线程任务的
不同点:
call方法有返回值,而且有异常可以throws,因为他的父类抛了throws
run方法没有返回值,而且有异常不可以throws,因为它的父类没有抛throws
4.Callable可以结合线程池使用:
Future<T> submit(Callable<T> task)
返回值:Future接口用于接收call方法的返回值
Future中有一个方法,是将接收过来的结果获取出来: V get()
5.注意:
a.实现Callable时需要指定泛型<V>
b.泛型:用于指定我们操作什么类型的数据,<>中只能写引用数据类型,如果泛型不写,默认时Object类型数据
c.实现Callable接口时,指定的泛型是什么类型的,重写的call方法返回值就是什么类型的
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "胡图图不糊涂";
}
}
public class Test03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(2);
Future<String> future = es.submit(new MyCallable());
System.out.println(future.get());
es.shutdown();
}
}
需求:创建两个线程任务,一个线程任务完成1-100的和,一个线程任务返回一个字符串
public class MySum implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Integer sum = 0;
for (int i = 1; i <= 100; i++) {
sum+=i;
}
return sum;
}
}
public class MyString implements Callable<String> {
@Override
public String call() throws Exception {
return "哇啊哈哈哈哈哈!";
}
}
public class Test04 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(2);
Future<String> submit = es.submit(new MyString());
Future<Integer> submit1 = es.submit(new MySum());
System.out.println(submit.get());
System.out.println(submit1.get());
es.shutdown();
}
}
1.概述:定时器
2.构造:
Timer()
3.方法:
void schedule(TimerTask task,Date firstTime,long period)
task:抽象类,是Runnable的实现类
firstTime:从什么时间开始执行
period:每隔多长时间执行一次,设置毫秒值
void cancel():取消定时器任务
public class Test {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("啊哈哈哈");
}
},new Date(),1000L);
//timer.cancel(); 取消定时器任务
}
}
1.概述:是一个字符串,用来表示一种规则的字符串
2.作用:校验
3.比如:校验一个QQ号
不能是0开头
必须都是数字
5-15位
4.String中的一个方法:用来校验字符串是否符合正则表达式
boolean matches(String regex)
public class Exercise {
public static void main(String[] args) {
//匹配qq号
boolean b = "2462773479".matches("[1-9][0-9]{4,14}");
System.out.println(b);
}
}
java.util.regex.Pattern:正则表达式的编译表示形式。
正则表达式-字符类:[]表示一个区间,范围可以自己定义
语法示例:
1. [abc]:代表a或者b,或者c字符中的一个。
2. [^abc]:代表除a,b,c以外的任何字符。
3. [a-z]:代表a-z的所有小写字符中的一个。
4. [A-Z]:代表A-Z的所有大写字符中的一个。
5. [0-9]:代表0-9之间的某一个数字字符。
6. [a-zA-Z0-9]:代表a-z或者A-Z或者0-9之间的任意一个字符。
7. [a-dm-p]:a 到 d 或 m 到 p之间的任意一个字符
正则表达式-逻辑运算符
语法示例:
1. &&:并且
2. | :或者
正则表达式-预定义字符
语法示例:
1. "." : 匹配任何字符。(重点) 不能加[]
2. "\\d":任何数字[0-9]的简写;(重点)
3. "\\D":任何非数字[^0-9]的简写;
4. "\\s": 空白字符:[ \t\n\x0B\f\r] 的简写
5. "\\S": 非空白字符:[^\s] 的简写
6. "\\w":单词字符:[a-zA-Z_0-9]的简写(重点)
7. "\\W":非单词字符:[^\w]
正则表达式-数量词
语法示例:x代表字符
1. X? : x出现的数量为 0次或1次
2. X* : x出现的数量为 0次到多次 任意次
3. X+ : x出现的数量为 1次或多次 X>=1次
4. X{n} : x出现的数量为 恰好n次 X=n次
5. X{n,} : x出现的数量为 至少n次 X>=n次 x{3,}
6. X{n,m}: x出现的数量为 n到m次(n和m都是包含的) n=<X<=m
正则表达式-分组括号( ) (abc)
String类中和正则表达式相关的方法
boolean matches(String regex) 判断字符串是否匹配给定的正则表达式。
String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
String replaceAll(String regex, String replacement)把满足正则表达式的字符串,替换为新的字符
https://www.sojson.com/regex/generate
### 5.正则表达式-数量词
~~~java
正则表达式-数量词
语法示例:x代表字符
1. X? : x出现的数量为 0次或1次
2. X* : x出现的数量为 0次到多次 任意次
3. X+ : x出现的数量为 1次或多次 X>=1次
4. X{n} : x出现的数量为 恰好n次 X=n次
5. X{n,} : x出现的数量为 至少n次 X>=n次 x{3,}
6. X{n,m}: x出现的数量为 n到m次(n和m都是包含的) n=
正则表达式-分组括号( ) (abc)
String类中和正则表达式相关的方法
boolean matches(String regex) 判断字符串是否匹配给定的正则表达式。
String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
String replaceAll(String regex, String replacement)把满足正则表达式的字符串,替换为新的字符
https://www.sojson.com/regex/generate