多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
并发: 通过cpu 调度算法:让用户看上去同时执行,实际上从cup操作层面不是真正的同时。并发往往在场景中有
共用的资源,那么针对这个共用的资源往往产生瓶颈,我们会用Tps或 QPS 来反应这个系统的处理能力
线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,CPU 是不是够用即可。返过来,线程不安全就意味着线程的调度顺序会影响最终结果
同步: java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问为线程安全,来保证结果的准确。在保证结果准确的同时,提高性能,才是优先的程序。线程安全的优先级高压性能
各种状态一目了然,值得一提的是blocked 这个状态
线程在running 的过程中可能会遇到阻塞(Blocked ) 情况
1. 调用join() 和sleep() 方法,sleep () 时间结束或被打断,join() 中断 ,IO 完成都会回到Runnable 状态,等待JVM 的调度
2. 调用Wait (),使该线程处于等待池,直到join() 中断 ,直到notify() /notify () ,线程被唤醒放到锁定池,释放同步锁使线程回到可运行状态
3. 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。
此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。
Thread 相关方法
//当前线程可转让CPU 控制权,让别的就绪状态线程运行(切换)
public static Thread.yield();
//暂停一段时间
public static Thread.sleep();
//在一个线程中调用other。join(),将等待other执行完后才继续本线程
public join()
//后两个函数皆可以被打断
public interrupte();
线程让步 --yield
yield() 方法和sleep()方法有点相似,它也是Thread 类提供的一个静态方法,它也可以
让当前正在执行的线程暂停,让出CPU资源给其他的线程。但是和sleep()方法不同的是,它不会进入到阻塞状态,而是进入到就绪状态,yield()方法只是让当前线程暂停一下,重新进入就绪的
线程池中,让系统的线程调度器重新调度一次,完全可能出现这样的情况,当某个线程调用yield()方法之后,线程调度器又将其调度出来重新进入到运行状态执行。
实际上,当某个线程调用了yield()方法暂停之后,优先级与当前线程相同,或者优先级比当前线程更高的就绪状态的线程更有可能获得执行的机会,当然,只是有可能,因为我们不可能精确的干涉CPU调度线程
sleep() 方法和yield () 方法的区别
(1).sleep 方法暂停当前线程后,会进入阻塞状态,只有当睡眠时间到了,才会转入就绪状态。
而yield方法调用后,是直接进入就绪状态,所以有可能刚进入就绪状态,又被调度到运行状态
(2).sleep 方法声明抛出InterrupteException ,所以调用sleep 方法的时候要捕获该异常,或者显示声明出该异常,而yield方法则没有声明抛出任务异常
(3).sleep方法比yield 方法有更好的可移植性,通常不要依靠yield方法来控制并发线程的执行
线程合并--join
线程的合并的含义就是将几个并行线程合并为一个单线程执行,应用场景是当一个线程必须等待另一个线程执行完毕才能执行时,Thread 类提供了join方法来完成这个功能注 意,它不是静态方法
线程通信:
1.借助于Object 类的wait() ,notify()和notifyAll () 实现通信
线程执行wait()后,就放弃了运行资格,处于冻结状态
线程运行时,内存中会建立一个线程池,冻结状态的线程都存在于线程池中,
notify() 执行时唤醒的也是线程池中的线程,线程池中有多个线程时唤醒第一个被冻结的线程
notifyAll(),唤醒线程池中所有线程
注意:
(1) wait() ,notify(),notifyAll()都用在同步里面,因为这三个函数对持有锁的线程进行操作,而只是同步才有锁,所以要使用在同步中;
(2) wait(),noyify(),notfyAll(),在使用时必须标识它们所操作的线程持有的锁,因为等待和唤醒必须是同一锁下的线程,而锁可以是任意对象,
所以这三个方法都是object类中的方法
synchronize 单独使用 代码块: 如下,在多线程环境下,synchronize 块中的方法获取lock实例monitor ,如果实例相同那么只有一个线程执行该块内容 public class Thread1 implement Runnable { Object lock; public void run () { synchronize (lock) { ...do.something } } } 直接用于方法:相当于上面代码中用lock来锁定的效果,实际获取的是Thread1 类monitor 。更进一步,如果修饰的是static方法,则锁定该类所有实例 public class Thread1 implements Runnable { public synchronize void run() { ..do something } } synchronize .wait ,notify 结合:典型场景生产者消费者问题 /* 生产者生产出来的产品交给店员 */ public synchronize void produce () { if(this.product>=MAX_PRODCT) { try { wait(); System.out.println("产品已满,请稍候再生产"); } catch(InterruptedException e) { e.printStackTrace(); } return; } this.product++; System.out.println("生产者生产第"+this.product+"个产品"); notifyAll();//通知等待区的消费者可以取出产品了 } /** 消费者从店员取产品 */ public synchronize void consume() { if(this.product<=MIN_PRODUCT) { try { wait(); System.out.println("缺货,稍候再取"); } catch( InterruptedException e) { e.printStackTrace(); } return; } System.out.printlm("消费者取走了第"+this.product+"个产品"); this.product--; notifyAll();//通知等待去的生产者可以生产产品了 }