线程状态
线程方法
线程停止
-
不推荐使用JDK提供的stop()、destroy()方法。【已废弃】
-
推荐线程自己停止下来
-
建议使用一个标志位进行终止变量,当flag=false,则终止线程运行
线程休眠sleep()
-
sleep(时间)指定当前线程阻塞的毫秒数
-
sleep存在InterruptedException异常
-
sleep时间达到后线程处于就绪状态
-
sleep可以模拟网络延时,倒计时等
-
每一个对象都有一个锁,sleep不会释放锁
-
线程不安全,多线程占用同一资源
线程礼让yield()
-
礼让线程,让当前正在执行的线程暂停,但不阻塞
-
将线程从运行状态转为就绪状态
-
让CPU重新调度,礼让不一定成功!看CPU心情
线程强制执行(插队)Join()
-
join() 合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
-
可以想象成插队
线程的优先级
-
Java提供一个线程调度器来监控程序启动后进入就绪状态的所有线程,按照优先级决定应该调度哪个线程来执行
-
线程优先级用数字表示,范围 1~10 :
-
Thread.MIN_PRIORITY=1 //priority
-
Thread.MAX_PRIORITY=1
-
Thread.NORM_PRIORITY=1
-
-
使用以下方式改变线程优先级
-
getPriority().setPriority(int XXX)
-
守护线程
-
线程分为用户线程和守护线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕
-
如,后台记录操作日志、监控内存,垃圾回收等待...
Thread thread = new Thread(); thread.setDaemon(true);//默认false为用户线程
线程同步
-
多个线程操作同一个资源
-
形成条件:队列+锁
-
锁机制:synchronized
三大线程不安全案例
线程之间互不影响
-
不安全的买票-出现负数
-
3个人买10张票
-
最后一张票都认为还有,一起买
-
造成剩余票1、0、-1的情况
-
-
不安全的取钱
-
两个人取钱,账户
-
sleep()放大问题的发生性
-
余额出现负数,银行送钱
-
-
线程不安全的集合
-
两个数组同一时间操作同一位
-
使用sleep()夸张化
-
把两个数组添加到了统一位置
-
同步方法 synchronized
-
保证安全
-
synchronized默认锁的是this,就是他本身,所以无需指定同步监视器。(仍然有可能造成负数发生)
-
每个对象对应一把锁
-
方法里面需要修改的内容才需要锁(只读不需要):同步块
-
锁的太多,浪费资源
同步块
synchronized(Obj){}
-
Obj为 “同步监视器”,可以为任何对象,推荐使用共享资源
-
锁的对象就是变化的量,需要增删改的对象
-
同步方法(同步本身)没用的情况下,可以用同步块
-
第一个线程访问同步监视器,锁定
JUC并发类
package com.archforce.aclub.forum.controller.activity; import java.util.concurrent.CopyOnWriteArrayList; //测试JUC安全类型的集合 public class TestJuc { public static void main(String[] args) { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
死锁
相互持有对方的锁,并尝试获取对方资源发生的阻塞现象
四个必要条件
package com.archforce.aclub.forum.controller.activity; //相互持有对方的锁,并尝试获取对方资源发生的阻塞现象 public class DeadLock { public static void main(String[] args) { Makeup g1 = new Makeup(0,"灰姑娘"); Makeup g2 = new Makeup(1,"白雪公主"); g1.start(); g2.start(); } } //口红 class Lipstick{} //镜子 class Mirror{ } //化妆 class Makeup extends Thread{ //需要的资源只有一份,勇static来保证 static Lipstick lipstack = new Lipstick(); static Mirror mirror = new Mirror(); int choice;//选择 String girlName;//使用化妆品的人 Makeup(int choice,String girlName){ this.choice=choice; this.girlName=girlName; } @Override public void run(){ //化妆 try { makeup(); } catch (InterruptedException e) { e.printStackTrace(); } } //化妆,互相持有对方的锁,就是需要拿到对方的资源 private void makeup() throws InterruptedException { if(choice==0){ synchronized (lipstack){ //获得口红的锁 System.out.println(this.girlName+"获得口红的锁"); Thread.sleep(1000); synchronized (mirror){ //一秒钟后想获得镜子的锁 System.out.println(this.girlName+"获得镜子的锁"); } } } else{ synchronized (mirror){ //获得镜子的锁 System.out.println(this.girlName+"获得镜子的锁"); Thread.sleep(2000); synchronized (lipstack){ //一秒钟后想获得口红的锁 System.out.println(this.girlName+"获得口红的锁"); } } } } }
解决办法:将synchronized (mirror){}方法放在synchronized (lipstack){}方法外即可,两者对应修改
Lock锁
-
每次只能有一个线程对Lock对象加锁
-
常用的ReentranLock(可重入锁)类实现了Lock,拥有和synchronized相同的并发性和内存语义,可以显示加锁,定义锁
生产者消费者模式(问题)
-
生产者:负责生产数据的模块(可能是方法、对象、线程、进程)
-
消费者:负责处理数据的模块(可能是方法、对象、线程、进程)
-
解决方法1:缓冲区:消费者不能直接使用生产者的数据,他们之间有个“缓冲区”
-
解决方法2:信号灯法(红灯停、绿灯行)
package com.archforce.aclub.forum.controller.activity; //生产者消费者模型 -> 利用缓冲区解决:管程法 //生产者、消费者、产品、缓冲区 public class TestPC { public static void main(String[] args) { SynContainer container = new SynContainer(); new Productor(container).start(); new Consumer(container).start(); } } //生产者 class Productor extends Thread{ SynContainer container; public Productor(SynContainer container){ this.container=container; } //生产 @Override public void run(){ for (int i = 0; i < 100; i++) { container.push(new Chicken(i)); System.out.println("生产了"+i+"只鸡"); } } } //消费者 class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container){ this.container=container; } //消费 @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println("消费了-----"+container.pop().id+"只鸡"); } } } //产品 class Chicken{ int id;//产品编号 public Chicken(int id){ this.id=id; } } //缓冲区 class SynContainer{ //需要一个容器大小 Chicken[] chickens = new Chicken[10]; //容器计数器 int count = 0; //生产者放入产品 public synchronized void push(Chicken chicken){ //如果容器满了,就需要等待消费者去消费 if(count==chickens.length){ //通知消费者消费,生产等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有满,我们就需要丢入产品 chickens[count] = chicken; count++; //可以通知消费者消费了 this.notifyAll(); } //消费者消费产品 public synchronized Chicken pop(){ //判断能否消费 if(count==0){ //等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果可以消费 count--; Chicken chicken = chickens[count]; //吃完了,通知生产者生产 this.notifyAll(); return chicken; } }
使用线程池
package com.archforce.aclub.forum.controller.activity; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //测试线程池 public class TestPool { //创建线程池 public static void main(String[] args) { //1、创建服务,线程池 ExecutorService service = Executors.newFixedThreadPool(10); //执行 service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //关闭连接 service.shutdown(); } } class MyThread implements Runnable{ @Override public void run(){ System.out.println(Thread.currentThread().getName()); } } /** * 输出结果 * pool-1-thread-3 * pool-1-thread-4 * pool-1-thread-1 * pool-1-thread-2 */