多线程Thread二
3.4 线程礼让 yeild
- 暂停当前正在执行的线程,但不阻塞
 - 将线程从运行状态转为就绪状态
 - 让cpu重新调度,重新竞争,礼让不易i的那个成功,看CPU心情
使用场景:执行某项复杂的任务时,如果担心占用资源过 
package thread;
import java.text.SimpleDateFormat;
public class TestYield {
	public static void main(String[] args) {
		MyYield myYield = new MyYield();
		new Thread(myYield,"a").start();
		new Thread(myYield,"b").start();
	}
	
	
}
class MyYield implements Runnable{
	public void run() {
		System.out.println(Thread.currentThread().getName()+" start to run");
		Thread.yield();//yield
		System.out.println(Thread.currentThread().getName()+" stop to run");
	}
	
	
}
3.5 Join
*原来主线程和子线程是并行关系,一旦使用join方法后就会变成串行关系
*主线程调用子线程的join()方法时,子线程插队,此时执行子线程阻塞主线程,待子线程完成后,再执行主线程
package Thread;
//测试join插队
public class TestJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("线程vip来了 "+i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin =  new TestJoin();
        Thread subThread = new Thread(testJoin);
        subThread.start();
        for (int i = 0; i < 100; i++) {
            if(i == 10){
                subThread.join();
            }
            System.out.println("main " + i );
        }
    }
}
3.7 线程状态观测
- Thread.state
- NEW
尚未启动的线程处于此状态 - RUNNABLE
在Java虚拟机中执行的线程处于此状态 - BLOCKED
被阻塞等待监视器锁定的线程处于此状态 - WAITTING
正在等待另一个线程执行特定动作的线程处于此状态 - TIMED_WAITTING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态 - TERMINATED
已退出的线程处于此状态
一个线程可以在给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态. 
 - NEW
 
package Thread;
public class TestState {
    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();
                }
                System.out.println("//////");
            }
        });
        //观察新生状态
        Thread.State state = thread.getState();
        System.out.println(state);
        //观察启动后
        thread.start();
        state = thread.getState();
        System.out.println(state);
        //只要线程不终止,就一直输出状态
        while(state != Thread.State.TERMINATED){
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);
        }
        //死亡之后的线程就不能再启动了
        //thread.start();
    }
}
对应的输出结果,在sleep是对应 TIMED_WATTING状态,线程死亡后不能再次启动
NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
//////
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
//////
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
//////
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
//////
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
//////
TERMINATED
Process finished with exit code 0
3.8 线程优先级
- 所有线程启动后进入就绪状态,此时java线程调度器按照优先级决定应该调用哪个线程来执行
 - 优先级范围1~10, 优先级越高中奖率越高,被CPU选中概率越大。但并不意味着低优先级的线程不能先执行,主要看CPU心情
- Thread.MIN_PRIORITY = 1 (最小)
 - Thread.MAX_PRIORITY = 10(最大)
 - Thread.NORM_PRIORITY = 5 (正常默认)
 
 - 改变或获取优先级方法
getPriority().setPriority(int xxx) - 优先级设置应该在start之前
 
package Thread;
public class TestPriority {
    public static void main(String[] args) {
        //打印主线程默认优先级,改不了的
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
      MyPriority myPriority  = new MyPriority();
       Thread t1 = new Thread(myPriority,"t1");
       Thread t2 = new Thread(myPriority,"t2");
       Thread t3 = new Thread(myPriority,"t3");
       Thread t4 = new Thread(myPriority,"t4");
       Thread t5 = new Thread(myPriority,"t5");
       Thread t6 = new Thread(myPriority,"t6");
       //先设置一下优先级再start
        t1.start();
        t2.setPriority(1);
        t2.start();
        t3.setPriority(4);
        t3.start();
        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();
  /*      t5.setPriority(-1);
        t5.start();
        t6.setPriority(13);
        t6.start();*/
    }
}
class MyPriority implements Runnable{
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}
3.9 守护线程
- 线程分为用户线程和守护线程
 - 虚拟机必须确保拥核线程执行完毕
 - 虚拟机不用确保守护线程执行完毕
 - 应用举例如:后台记录操作日志,监控内存,垃圾回收gc等...
 - 默认创建的都是用户线程,只有手动设置了true才是守护线程
threadName.setDaemon(true);
例 人生不过300天 
package Thread;
//测试守护线程,
public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread thread = new Thread(god);
        //默认创建的都是用户线程,只有手动设置了true才是守护线程
        thread.setDaemon(true);
        thread.start();
        new Thread(you).start();
    }
}
//God
class God implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("god monitor you");
        }
    }
}
//你
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("开心每一天");
        }
        System.out.println("goodbye world");
    }
}
4 线程同步
并发 多个线程操作同一个资源,如买票,取钱
解决 队列+锁 保证线程同步的安全性
4.1 线程同步
锁机制 synchronized,当一个线程获得对象的锁,独占资源,其他线程必须等待,使用后释放锁,缺点:
- 其他线程挂起---一个线程持有锁会导致其他所有需要此锁的线程挂起
 - 锁处理耗时---在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时
 - 优先级倒置---如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
三大不安全案例
例1 买票
每个线程在自己的工作内存交互,两线程都把余票数据复制到自己内存中,剩余一张票的时候,连续自减两次就出现了负票 
package thread;
public class UnsafeBuyTicket {
	public static void main(String argvs[]){
		BuyTicket buyTicket = new BuyTicket();
		new Thread(buyTicket,"xiaoming").start();
		new Thread(buyTicket,"xiaohong").start();
		new Thread(buyTicket,"xiaolan").start();
	}
}
class BuyTicket implements Runnable{
	private int ticketNums = 10;
	boolean flag = true;
	@Override
	public void run() {
		while(flag){
			buy();
		}
	}
	
	private void buy(){
		
		if(ticketNums<=0){
			flag = false;
			return;
		}
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"tack the "+ ticketNums--+" ticket");
	}
	
}
result:
xiaohongtack the 10 ticket
xiaolantack the 8 ticket
xiaomingtack the 9 ticket
xiaohongtack the 7 ticket
xiaolantack the 6 ticket
xiaomingtack the 5 ticket
xiaohongtack the 4 ticket
xiaomingtack the 3 ticket
xiaolantack the 2 ticket
xiaohongtack the 1 ticket
xiaomingtack the 0 ticket
xiaolantack the -1 ticket
例2. 两人同时取一个账号里的钱
package thread;
public class UnsafeBank {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Account account = new Account("fund", 100);
		Drawing you = new Drawing(account, 50,"you");
		Drawing wife = new Drawing(account, 100,"wife");
		
		you.start();
		wife.start();
	}
}
class Account {
	String name;
	int money;
	public Account(String name, int money) {
		this.name = name;
		this.money = money;
	}
}
class Drawing extends Thread {
	Account account;
	int drawingMoney;
	public Drawing(Account account, int drawingMoney, String name) {
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;
		
	}
	public void run(){
		if (account.money-drawingMoney<0){
			System.out.println(Thread.currentThread().getName()+"not enough, can't withdraw");
			return;
		}
		try {
			//写在判断条件后面,放大问题发生可能性
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
		account.money -= drawingMoney;
		
		System.out.println(account.name+ " balance is "+ account.money);
		//Thread.currentThread().getName() ==  this.getName(), current class extend Thread
		System.out.println(this.getName() +" money in hand is "+ drawingMoney);
	}
}
result:
fund balance is -50
you money in hand is 50
fund balance is -50
wife money in hand is 100
例3 ArrayList是线程不安全的
package thread;
import java.util.ArrayList;
import java.util.List;
public class UnsafeList {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		for(int i =0; i<10000;i++){
//java8后写lamda表达式
/*			new Thread(()->{
				list.add(Thread.currentThread().getName());
			}).start();*/
                        
                        //多个线程名字添加到list的同一位置,覆盖掉了
			new Thread(new MyThread(list)).start();
		}
               //等10s所有子线程都结束再统计存进去的线程总数
               try {
			Thread.sleep(10000);
		  } catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.print(list.size());
	}
}
class MyThread implements Runnable{
	List<String> list = null;
	public MyThread(List<String> list){
		this.list = list;
	}
	public void run(){
		list.add(Thread.currentThread().getName());
	}
}
result: 9978
4.2 同步方法
- 类似提出private关键字,可以保证数据只能在类内访问
同步使用的synchronized也是关键字,利用锁和队列保证线程安全。其分为 synchronized方法和synchronized块
同步方法: public synchronized void method(int args){} - 每个对象有一把锁,synchronized方法必须获取调用该方法的对象的锁才能执行,否则线程会阻塞
 - synchronized方法一旦执行就独占该锁,直到方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
 - 缺点: 一个方法声明位synchronized大大影响效率
![]()
例 1 买票方法加上synchronized 
package thread;
public class UnsafeBuyTicket {
	public static void main(String argvs[]){
		BuyTicket buyTicket = new BuyTicket();
		new Thread(buyTicket,"xiaoming").start();
		new Thread(buyTicket,"xiaohong").start();
		new Thread(buyTicket,"xiaolan").start();
	}
}
class BuyTicket implements Runnable{
	private int ticketNums = 10;
	boolean flag = true;
	@Override
	public void run() {
		while(flag){
			buy();
		}
	}
	
	// lock this object
	private synchronized void buy(){
		
		if(ticketNums<=0){
			flag = false;
			return;
		}
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" take the "+ ticketNums--+" ticket");
	}
	
}
4.3 同步代码块
- 语法 synchronized(Obj){}
 - Obj 同步监视器
- Obj可以是任何对象,但是推荐使用共享资源对象
 - 同步方法中无需指定同步监视器,其监视器是this或者class(反射中讲解)
例 银行取钱,不是锁取钱的对象,而是锁账户 
 
package thread;
public class UnsafeBank {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Account account = new Account("fund", 100);
		Drawing you = new Drawing(account, 50,"you");
		Drawing wife = new Drawing(account, 100,"wife");
		
		you.start();
		wife.start();
	}
}
class Account {
	String name;
	int money;
	public Account(String name, int money) {
		this.name = name;
		this.money = money;
	}
}
class Drawing extends Thread {
	Account account;
	int drawingMoney;
	public Drawing(Account account, int drawingMoney, String name) {
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;
		
	}
	
	//It's no value to synchronized run method. it locks Drawing object, not account object
	public void run(){
                //锁的变化的量,针对增删改操作,不针对查
		synchronized(account){
			if (account.money-drawingMoney<0){
				System.out.println(Thread.currentThread().getName()+"not enough, can't withdraw");
				return;
			}
			try {
				//magnify issue
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			account.money -= drawingMoney;
			
			System.out.println(account.name+ " balance is "+ account.money);
			//Thread.currentThread().getName() ==  this.getName(), current class extend Thread
			System.out.println(this.getName() +" money in hand is "+ drawingMoney);
			
		}
		
	}
}
例3 list 锁
package thread;
import java.util.ArrayList;
import java.util.List;
public class UnsafeList {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < 10000; i++) {
			/*
			 * new Thread(()->{ synchronized(list){
			 * list.add(Thread.currentThread().getName()); } }).start();
			 */
			new Thread(new MyThread(list)).start();
		}
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.print(list.size());
	}
}
class MyThread implements Runnable {
	List<String> list = null;
	public MyThread(List<String> list) {
		this.list = list;
	}
	public void run() {
                //add的步骤锁住
		synchronized (list) {
			list.add(Thread.currentThread().getName());
		}
	}
}
result: 10000
JUC
package thread;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestJUC {
	public static void main(String[] args) {
		CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
		for(int i=0;i<10000;i++){
			new Thread(new MyThread(list))
		}
	}
}
class MyThread implements Runnable {
	List<String> list = null;
	public MyThread(List<String> list) {
		this.list = list;
	}
	public void run() {
		synchronized (list) {
			list.add(Thread.currentThread().getName());
		}
	}
}
扩展 java.util.concurrent并发包下的类使用
例 CopOnWriteArrayList
package thread;
        import java.util.concurrent.CopyOnWriteArrayList;
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());
    }
}
4.4 死锁
多个线程各自占有一些共享资源,并相互等待其他线程占有的资源才能运行结束,而导致停止执行的情形。
如 小孩A拥有车希望小孩B给自己船后才不要车,小孩B拥有船也希望小孩A先给他车才能让出船。
例 口红和镜子两个资源
package Thread;
//死锁:多个线程互相抱着对方需要的资源,然后形成僵持
public class DeadLock {
    public static void main(String[] args) {
        new Makeup(0,"xiaohong").start();
        new Makeup(1,"xiaolan").start();
    }
}
class Lipstick{
}
class Mirror{
}
class Makeup extends Thread{
    //static 共享的
    static Lipstick lipstick = 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 (lipstick){
                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(1000);
                synchronized (lipstick){
                    System.out.println(this.girlName+ " 获得口哦那个的锁");
                }
            }
        }
    }
}
结果程序运行卡住,不能停止
- 产生死锁的四个必要条件
 
- 互斥条件:一个资源每次只能被一个线程是使用
 - 请求与保持条件: 一个线程因请求资源而阻塞时,对已获得的资源保持不妨
 - 不剥夺条件: 进程已获得资源,在为使用完之前,不能强行剥夺
 - 循环等待条件: 若干线程之间形成头尾相接的循环等待资源关系
破坏任意一个或多个条件即可避免死锁 
4.5 Lock (锁)
- 从JDK5开始 java提供显示定义同步锁LOCK(synchronized)
 - java.util.concurrent.locks.Lock接口,每次只能有一个线程对Lock对象加锁,线程访问共享资源之前应先获得Lock对象
 - ReentrantLock类(可重入锁)实现了Lock, 常用来显示加锁,释放锁
语法
class A{
private final ReentrantLock lock = new ReenTrantLock();
public void m(){
lock.lock(); //加锁
try{
//保证线程安全的代码;
}
finally{
lock.unlock(); //解锁
//如果同步代码有异常,要将unlock()写入finally语句块
}
例: 
package Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
	public static void main(String[] args) {
		TestLock2 testLock2 = new TestLock2();
		new Thread(testLock2, "xiaoming").start();
		new Thread(testLock2, "xiaohong").start();
		new Thread(testLock2, "xiaolan").start();
	}
}
class TestLock2 implements Runnable {
	int ticketNums = 10;
	// define lock
	private final ReentrantLock lock = new ReentrantLock();
	public void run() {
		while (true) {
			try {
				Thread.sleep(100);
				lock.lock();// lock
				
				if (ticketNums > 0) {
					System.out.println(Thread.currentThread().getName()
							+ " get the " + ticketNums-- + " ticket");
				} else {
					break;
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				lock.unlock(); // unlock
			}
		}
	}
}
**synchronized 与 lock的对比
- Lock是显示锁,手动开启锁关闭锁,synchronized是隐式锁,出了作用域自动释放
 - Lock只有代码块锁,synchronized 代码块—+方法锁
 - 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多子类)
 - 优先使用顺序
*Lock->同步代码块(已经进入了方法体,分配了相应资源)->同步方法(在方法体之外) 
4.6 线程协作
生产者消费者模式
4.6.1 线程通信
- 应用场景:生产者和消费者问题
- 对于仓库:假设仓库中只能放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
 - 对于生产者:如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止
 - 对于消费者:如果仓库中放有产品,则消费者取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。
 
 - 通信分析
- 线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
 - 生产者,没有生产产品之前,要通知消费者等待。生产产品之后,要通知消费者消费
 - 消费者,消费之后,要通知生产者消费结束,需要生产新的产品以供消费
 - 在生产者消费者问题中,仅有synchronized是不够的
虽然可以实现同步,但是不能实现线程之间的消息传递(通信) 
 - java提供的线程通信方法
- wait() 线程一直等待,直到其他线程通知,与sleep抱着锁睡觉不同,会释放锁
 - wait(long timeout) 指定等待毫秒数
 - notify() 唤醒一个处于等待状态的线程
 - notifyAll() 唤醒 同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度
注意:均是Object类的方法,都知道能在同步方法或者同步代码块中使用,否则会抛出异常illegalMonitorStateException 
 - 解决方式1--管程法
- 生产者:负责生产数据的模块(可能是方法,对象,线程,进程)
 - 消费者:负责处理数据的模块 (可能是方法,对象,线程,进程)
 - 缓冲区: 消费者不能直接使用生产者的数据,他们之间有个缓冲区
![]()
 
 - 解决方式2 --信号灯法
设置标志位,true的时候进行,false等待 
4.6.2 管程法
产品 只提供属性
生产者 线程里只循环生产数据 (缓冲区对象作为属性)
消费者 线程里只循环处理消费(缓冲区对象作为属性)
缓冲区 提供生产方法和消费方法,并设置判定条件指定wait和notifyAll 动作
package Thread;
//测试生产者消费者模型-> 利用缓冲区解决问题:管程法
//生产者,消费者,缓冲区
public class TestPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Producer(container).start();
        new Consumer(container).start();
    }
}
//生产者 线程里只顾生产
class Producer extends Thread{
    SynContainer container;
    public Producer(SynContainer container) {
        this.container = container;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了第"+ i +"只鸡");
            container.push(new Chicken(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 = 0;
    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;
        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;
    }
}
4.6.3 信号灯法
生产者 只负责循环生产
消费者 只负责循环消费
产品  除了属性还提供生产和消费的方法,标志位flag只有true和flase两个值,取代了管程法中的缓冲区,但是只能生产一个产品
同一标志位值,生产者和消费者采取相反的两种操作
package Thread;
//测试生产者消费者问题2:信号灯法,标志位
public class TestPC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}
//生产者-->演员
class Player extends Thread{
    TV tv;
    public Player(TV tv) {
        this.tv = tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2==0){
                this.tv.play("综艺");
            }else{
                this.tv.play("电视剧");
            }
        }
    }
}
//消费者-->观众
class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv) {
        this.tv = tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}
// 产品-->节目
class TV{
    //演员拍戏的时候观众等待
    //观众观看的时候,这个敬业演员等待评价反馈再投入下次拍戏
    String program;
    //标志位是否该拍戏,true的时候演员拍戏,观众等待。false 演员录完了,观众观看。
    // 生产者和消费者标志位相同时,采取相反的行动
    boolean flag = true;
    
    //表演方法,提供给生成者
    public synchronized void play(String program){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //演员表演完,通知观众观看
        System.out.println("演员表演完了"+program);
        this.notifyAll();
        this.program = program;
        this.flag = !this.flag;
    }
    //观看,提供给消费者
    public synchronized void watch(){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //观众看完戏,通知演员拍戏
        System.out.println("观看了"+ program);
        this.flag = !this.flag;
        this.notifyAll();
    }
}
4.7 线程池
- 背景: 经常创建和销毁线程,消耗特别大的资源,对性能影响很大
 - 思路: 提前创建多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用。类似生活中的公共交通
 - 好处:
- 提高响应速度(减少了创建新线程的时间)
 - 降低资源消耗 (重复利用线程池中的线程,不需要每次都创建)
 - 便于线程管理
- corePoolSize:核心池的大小
 - maximumPoolSize: 最大线程数
 - keepAliveTime: 线程没有任务时最多保持多长时间后会终止
 
 
 - 使用线程池
- jdk 1.5起提供ExecutorService 和 Executors
 - ExecutorService: 真正的线程池接口,常见子类 ThreadPoolExecutor
- void execute(Runnable command):执行实现Runnable的线程,没有返回值
 Future submit(Callable task):执行实现Callable接口的线程任务,有返回值 - void shutdown(): 关闭线程池
 
 - Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池
ExecutorService service = Executors.newFixedThreadPool(nThreads)创建线程池
例 runable线程池 
 
package Thread;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThread implements Runnable{
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        MyThread mythread = new MyThread();
        service.execute(mythread);
        service.execute(mythread);
        service.execute(mythread);
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+ " "+i);
        }
    }
}
Callable例子参前2.3
    博客有点圆
                    
                


                
            
        
浙公网安备 33010602011771号