线程就是独立的执行路径;
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()称之为主线程,为系统的入口,用于执行整个程序在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的;
对同份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
线程会带来额外的开销,如cpu调度时间,并发控制开销;
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程的三种创建方式
1、Thread类:(实现了Runnable接口)
2、Runnable接口:
3、Callable接口:
Thread
1、继承Thread类
2、重写run方法
3、调用start方法开启线程
public class TestThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println("run*************");
}
}
public static void main(String[] args) {
//创建线程对象
TestThread tt1 = new TestThread();
//调用start()启动线程
tt1.start();
for (int i = 0; i < 2000; i++) {
System.out.println("main");
}
}
}
Runnable
public class Race implements Runnable{
static private int length = 1000;
static private String winName = null;
@Override
public void run() {
for (int i = 0; winName==null; i++) {
win(i);
if(Thread.currentThread().getName().equals("兔子")){
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
private void win(int i){
if(i == length && winName == null){
winName = Thread.currentThread().getName();
}
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
System.out.println(winName+"is the winner!");
}
}
静态代理
Lambda表达式
Functional Interface函数式接口
函数式接口:只包含一个抽象方法的接口;
对于函数式接口我们可以通过lambda表达式来创建该接口的对象
线程休眠----sleep
sleep指定当前线程阻塞的毫秒数;
sleep存在InterruptedException异常;
sleep时间结束后线程进入就绪状态;
sleep可以模拟网络延时,倒计时等;
每一个对象都有一个锁,sleep不会释放锁。
线程礼让----yield
线程强制执行----join
线程状态
new:线程对象一旦创建就进入到新生状态;
就绪状态:调用start()方法,线程立即进入就绪状态,但不意味着立即调度执行;
运行状态:进入运行状态,线程才真正执行线程体的代码块
阻塞状态:党调用sleep,wait或同步锁定时,线程进入阻塞状态,就是代码不往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu调度执行;
dead:线程中断或结束,一旦进入死亡状态,就不能再次启动。
public class TestState {
public static void main(String[] args) {
Thread ts = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("###########");
});
Thread.State state = ts.getState();
System.out.println(state);
ts.start();
state = ts.getState();
System.out.println(state);
while(state != Thread.State.TERMINATED){
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
state = ts.getState();
System.out.println(state);
}
}
}
线程优先级
java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行;
线程的优先级用数字表示,范围1~10;
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
获取优先级:
getPriority()
setPriority(int )
守护(daemon)线程
线程氛围用户线程和守护线程;
虚拟机必须保证用户线程执行完毕;(main……)
虚拟机不用等待守护线程执行完毕;(gc……)如后台记录操作日志,监控内存,垃圾回收等待……
public class TestDeamon {
public static void main(String[] args) {
Thread tu = new Thread(()->{
for (int i = 0; i < 1000; i++) {
System.out.println("信仰");
}
System.out.println("完成!!!!");
});
Thread td = new Thread(()->{
while(true){
System.out.println("守护线程###");
}
});
//守护线程
td.setDaemon(true);
td.start();
tu.start();
}
}
线程同步
多个线程操作同一个资源。
队列和锁
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可.
存在以下问题:
一个线程持有锁会导致其他所有需要此锁的线程挂起;
在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时引起性能问题
如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题
synchronized
同步块
synchronized(Obj){
}
死锁
产生死锁的四个必要条件
1.互斥条件:一个资源每次只能被一个进程使用。
2.请求与保持条件:—个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
Lock锁
ReentrantLock可重用锁
Lock是显式锁(手动开启和关闭锁,别忘记关闭锁);synchronized是隐式锁,出了作用域自动释放
Lock只有代码块锁,synchronized有代码块锁和方法锁
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
优先使用顺序:Lock>同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)
class A{
private final ReentrantLock lock = new ReentrantLock();
public void m(){
lock.lock();
try{
}finally(){
lock.unlock();
}
}
}
线程协作
生产者消费者问题
线程通信
wait():表示线程一直等待,直到其他线程通知,会释放锁,与sleep不同;
wait(long timeout):指定等待的毫秒数;
notify():唤醒一个处于等待状态的线程 ;
notifyAll():唤醒同一对象上所有调用wait()方法的线程,优先级高的线程优先调度。
均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException
public class TestPC {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
Producter producter = new Producter(synContainer);
Consumer consumer = new Consumer(synContainer);
Thread TP = new Thread(producter);
Thread TC = new Thread(consumer);
TP.start();
TC.start();
}
}
//生产者
class Producter implements Runnable{
SynContainer synContainer;
public Producter(SynContainer synContainer){
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.push(new Production("产品"+i));
System.out.println("生产"+i);
}
}
}
class Consumer implements Runnable{
SynContainer synContainer;
public Consumer(SynContainer synContainer){
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.pop();
System.out.println("消费"+i);
}
}
}
class Production{
String id;
public Production(String id){
this.id = id;
}
}
class SynContainer{
Production[] synContainer = new Production[10];
private static int count = -1;
public synchronized void push(Production production){
if(count >= 9){
System.out.println("容器满,生产者等待");
try {
notifyAll();
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synContainer[++count] = production;
}
public synchronized Production pop(){
if(count<0){
System.out.println("容器空,消费者等待");
try {
notifyAll();
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return synContainer[count--];
}
}
public class TestPC2 {
public static void main(String[] args) {
TV tv = new TV();
new Thread(new player(tv)).start();
new Thread(new watcher(tv)).start();
}
}
class player implements Runnable{
TV tv;
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
tv.play("广告");
}else{
tv.play("表演");
}
}
}
public player(TV tv){
this.tv = tv;
}
}
class watcher implements Runnable{
TV tv;
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
tv.watch("观看广告");
}else{
tv.watch("观看表演");
}
}
}
public watcher(TV tv){
this.tv = tv;
}
}
class TV{
//true表演,false不表演。
boolean flag = true;
public synchronized void play(String perform){
if(!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notifyAll();
System.out.println(perform);
flag = !flag;
}
public synchronized void watch(String perform){
if(flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notifyAll();
System.out.println(perform);
flag = !flag;
}
}